none
Function not outputting data RRS feed

  • Question

  • Hi guys this may be a silly question but I am fairly new to powershell and could use some help. So I have wrapped a script within a function and am calling this function from within my script. When I had the code contained within the function in another script and was calling that script the output worked perfectly. However, since I have tried merging the two scripts the output is no longer working. Please see the code below and let me know what I have done wrong or am missing. Thanks.

    $FoundKeys = SearchReg -StartKey $i -Pattern $j -MatchData
    $FoundKeys | Format-List | Out-File $Log -Encoding ascii -Append


    Function SearchReg
    {
        param(
            [parameter(Position=0,Mandatory=$TRUE)]
                [String] $StartKey,
            [parameter(Position=1,Mandatory=$TRUE)]
                [String] $Pattern,
                [Switch] $MatchKey,
                [Switch] $MatchValue,
                [Switch] $MatchData,
                [UInt32] $MaximumMatches=0,
            [parameter(ValueFromPipeline=$TRUE)]
                [String[]] $ComputerName=$ENV:COMPUTERNAME
            )

        begin {
          $PIPELINEINPUT = (-not $PSBOUNDPARAMETERS.ContainsKey("ComputerName")) -and
            (-not $ComputerName)

          # Throw an error if -Pattern is not valid
          try {
            "" -match $Pattern | out-null
          }
          catch [System.Management.Automation.RuntimeException] {
            throw "-Pattern parameter not valid - $($_.Exception.Message)"
          }

          # You must specify at least one matching criteria
          if (-not ($MatchKey -or $MatchValue -or $MatchData)) {
            throw "You must specify at least one of: -MatchKey -MatchValue -MatchData"
          }

          # Interpret zero as "maximum possible number of matches"
          if ($MaximumMatches -eq 0) { $MaximumMatches = [UInt32]::MaxValue }

          # These two hash tables speed up lookup of key names and hive types
          $HiveNameToHive = @{
            "HKCR"               = [Microsoft.Win32.RegistryHive] "ClassesRoot";
            "HKEY_CLASSES_ROOT"  = [Microsoft.Win32.RegistryHive] "ClassesRoot";
            "HKCU"               = [Microsoft.Win32.RegistryHive] "CurrentUser";
            "HKEY_CURRENT_USER"  = [Microsoft.Win32.RegistryHive] "CurrentUser";
            "HKLM"               = [Microsoft.Win32.RegistryHive] "LocalMachine";
            "HKEY_LOCAL_MACHINE" = [Microsoft.Win32.RegistryHive] "LocalMachine";
            "HKU"                = [Microsoft.Win32.RegistryHive] "Users";
            "HKEY_USERS"         = [Microsoft.Win32.RegistryHive] "Users";
          }
          $HiveToHiveName = @{
            [Microsoft.Win32.RegistryHive] "ClassesRoot"  = "HKCR";
            [Microsoft.Win32.RegistryHive] "CurrentUser"  = "HKCU";
            [Microsoft.Win32.RegistryHive] "LocalMachine" = "HKLM";
            [Microsoft.Win32.RegistryHive] "Users"        = "HKU";
          }

          # Search for 'hive:\startkey'; ':' and starting key optional
          $StartKey | select-string "([^:\\]+):?\\?(.+)?" | foreach-object {
            $HiveName = $_.Matches[0].Groups[1].Value
            $StartPath = $_.Matches[0].Groups[2].Value
          }

          if (-not $HiveNameToHive.ContainsKey($HiveName)) {
            throw "Invalid registry path"
          } else {
            $Hive = $HiveNameToHive[$HiveName]
            $HiveName = $HiveToHiveName[$Hive]
          }

          # Recursive function that searches the registry
          function search-registrykey($computerName, $rootKey, $keyPath, [Ref] $matchCount) {
            # Write error and return if unable to open the key path as read-only
            try {
              $subKey = $rootKey.OpenSubKey($keyPath, $FALSE)
            }
            catch [System.Management.Automation.MethodInvocationException] {
              $message = $_.Exception.Message
              write-error "$message - $HiveName\$keyPath"
              return
            }

            # Write error and return if the key doesn't exist
            if (-not $subKey) {
              write-error "Key does not exist: $HiveName\$keyPath" -category ObjectNotFound
              return
            }

            # Search for value and/or data; -MatchValue also returns the data
            if ($MatchValue -or $MatchData) {
              if ($matchCount.Value -lt $MaximumMatches) {
                foreach ($valueName in $subKey.GetValueNames()) {
                  $valueData = $subKey.GetValue($valueName)
                  if (($MatchValue -and ($valueName -match $Pattern)) -or ($MatchData -and ($valueData -match $Pattern))) {
                    "" | select-object `
                      @{N="ComputerName"; E={$computerName}},
                      @{N="Key"; E={"$HiveName\$keyPath"}},
                      @{N="Value"; E={$valueName}},
                      @{N="Data"; E={$valueData}}
                    $matchCount.Value++
                  }
                  if ($matchCount.Value -eq $MaximumMatches) { break }
                }
              }
            }

            # Iterate and recurse through subkeys; if -MatchKey requested, output
            # objects only report computer and key (keys do not have values or data)
            if ($matchCount.Value -lt $MaximumMatches) {
              foreach ($keyName in $subKey.GetSubKeyNames()) {
                if ($keyPath -eq "") {
                  $subkeyPath = $keyName
                } else {
                  $subkeyPath = $keyPath + "\" + $keyName
                }
                if ($MatchKey -and ($keyName -match $Pattern)) {
                  "" | select-object `
                    @{N="ComputerName"; E={$computerName}},
                    @{N="Key"; E={"$HiveName\$subkeyPath"}},
                    @{N="Value"; E={}},
                    @{N="Data"; E={}}
                  $matchCount.Value++
                }
                # $matchCount is a reference
                search-registrykey $computerName $rootKey $subkeyPath $matchCount
                if ($matchCount.Value -eq $MaximumMatches) { break }
              }
            }

            # Close opened subkey
            $subKey.Close()
          }

          # Core function opens the registry on a computer and initiates searching
          function search-registry2($computerName) {
          # Write error and return if unable to open the key on the computer
          try {
              $rootKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Hive,
                $computerName)
            }
            catch [System.Management.Automation.MethodInvocationException] {
              $message = $_.Exception.Message
              write-error "$message - $computerName"
              return
            }
            # $matchCount is per computer; pass to recursive function as reference
            $matchCount = 0
            search-registrykey $computerName $rootKey $StartPath ([Ref] $matchCount)
            $rootKey.Close()
          }
        }

        process {
          if ($PIPELINEINPUT) {
            search-registry2 $_
          }
          else {
            $ComputerName | foreach-object {
              search-registry2 $_
            }
          }
        }
    }

    Wednesday, July 19, 2017 7:07 PM

Answers

  • I was being a bit tongue-in-cheek (I am, in fact, the author of that article--you're welcome).

    As jrv said, you have to define a function before you execute it.

    Move the lines of code where you call the function after the function.


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by LeeLee2cold Wednesday, July 19, 2017 8:03 PM
    Wednesday, July 19, 2017 7:48 PM
    Moderator

All replies

  • It's considered bad form to copy and paste code and not give credit to the author.

    Windows IT Pro - Searching the Registry with PowerShell

    What does "not working" mean? (When you say that something didn't work, you have to say how it didn't work.)

    -- Bill Stewart [Bill_Stewart]


    Wednesday, July 19, 2017 7:15 PM
    Moderator
  • "SearchReg" can only be called after the function has been loaded.


    \_(ツ)_/

    Wednesday, July 19, 2017 7:35 PM
  • Understood, I do not want credit for it I was just simply testing to see if it could be used within a script I am writing. I have copied over the comments from the original script. Now when I said that it is not working, I had mentioned above that it is no longer outputting the data. I am writing the output to a file and when I check the file there is no matching registry keys displayed. However, if I step through the script using the powershell ISE debugger it does display the matching registry keys within the log file. Why is this and how do I get the output to the log file?
    Wednesday, July 19, 2017 7:45 PM
  • I was being a bit tongue-in-cheek (I am, in fact, the author of that article--you're welcome).

    As jrv said, you have to define a function before you execute it.

    Move the lines of code where you call the function after the function.


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by LeeLee2cold Wednesday, July 19, 2017 8:03 PM
    Wednesday, July 19, 2017 7:48 PM
    Moderator
  • Oh ok lol I thought that was you. Thank you for that article and script as it is helping me to automate the eradication of a virus. Also your suggestion did resolve my issue. I knew it had to be something simply, just is a little different than what I am use to.
    Wednesday, July 19, 2017 8:03 PM
  • Sounds good, glad you got it working.

    -- Bill Stewart [Bill_Stewart]

    Wednesday, July 19, 2017 8:14 PM
    Moderator