I am writing a troubleshooting script to determine which IP addresses in our Domain are accessible by WMI, and which are not. The script will read a list of input parameters (about 18,000 lines), and will output to a file the IP address and the username
IP address, Username
Problem is, when the WMI error is thrown, it writes to the file
IP address, Get-WmiObject : The RPC server is unavailable. .....numerous lines of error
I would like to make it such that when a WMI error it thrown, it writes the following
IP address, "WMI ERROR"
And here is the modified code for reference
#script_modified.ps1
$abc = $args
$startInfo = $NULL
$process = $NULL
$standardOut = $NULL
<#Previously created password file in C:\Script\cred.txt, read-host -assecurestring | convertfrom-securestring | out-file C:\Script\cred.txt#>
$password = get-content C:\Script\cred.txt | convertto-securestring
$a = Get-Content "C:\Script\test_input.txt"
foreach ($b in $a){
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = "C:\script\script2.ps1 " + $b
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
$startInfo.Username = "service.infosec"
$startInfo.Domain = "Central"
$startInfo.Password = $password
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$standardOut = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
# $standardOut should contain the results of "C:\script\script2.ps1"
Add-Content C:\script\list_of_computers_in_DOMAIN.log $b","$standardOut
}
EDIT
#Hyper Anthony
I updated my code to the following
try{
$process.StartInfo = $startInfo
}
catch{
$message = "WMI ERROR"
}
finally{
$process.WaitForExit()
Add-Content C:\script\list_of_computers_in_DOMAIN.log $b","$message
}
And I get following errors:
Exception calling "WaitForExit" with "0" argument(s): "No process is associated with this object."
At C:\script\script_modified.ps1:36 char:29
+ $process.WaitForExit <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
How to fix?
EDIT:
Below is the updated code:
foreach ($b in $a){
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
...More Code...
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
try{
$process.Start() | Out-Null
$standardOut = $process.StandardOutput.ReadToEnd()
}
catch{
$standardOut = "WMI ERROR"
}
finally{
$process.WaitForExit()
Add-Content C:\script\list_of_computers_in_DOMAIN.log $b","$standardOut
}
}
There are no longer any errors that get output to the console, BUT, the output file is not as I wish.
When there is an WMI error, I would like the following line to be written
'sender-ip=10.10.10.10', WMI Error
But instead, the following is written
'sender-ip=10.10.10.10',Get-WmiObject : The RPC server is unavailable.
(Exception from HRESULT: 0x800706BA) ...many lines of error
or any other error may be printed instead of WMI Error.
Thanks once again!
Related
I have this PowerShell code.
Works good. But when I add more lines to db.csv, it doesn't work and return error code:
Exception calling "Open" with "1" argument(s): "Connection has been unexpectedly closed. Server sent command exit status 0.
Authentication log (see session log for details):
Using username "username".
Authentication failed."
At C:\Users\me\Desktop\testeScript\CollectLog.ps1:41 char:5
+ $session.Open($sessionOptions)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SessionRemoteException
When I have for example only two lines in db.csv the script works very well
HostName,IP
name1,10.10.1.1
name2,10.10.1.2
I try with 19 hostname and Ip addr line in CSV doc and works, but when I add only 1 more stopping works.
19 works
20+ doesn't work..
Any idea? (Thank you and sorry for my english)
Add-Type -Path "WinSCPnet.dll"
$Name = #()
$ip = #()
Import-Csv db.csv |`
ForEach-Object {
$Name += $_.HostName
$ip += $_.IP
}
$inputID = Read-Host -Prompt "Type ID"
if ($Name -contains $inputID)
{
$Where = [array]::IndexOf($Name, $inputID)
Write-Host "IP: " $ip[$Where]
}
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "$ip"
UserName = "username"
Password = "password"
GiveUpSecurityAndAcceptAnySshHostKey = "true"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Transfer files
$session.GetFiles("/C:/Program Files/Common Files/logs/Device.log", "E:\loguri\Log\Arhive\*").Check()
}
finally
{
$session.Dispose()
}
Compress-Archive -Path "E:\loguri\Log\Arhive\Device.log" -DestinationPath "E:\loguri\Log\Arhive\$inputID.zip" -Update
Remove-Item -Path "E:\loguri\Log\Arhive\Device.log" -Force
as Theo says you have no need to separate out your CSV into two arrays as you have. Import it like this
$db = import-csv 'db.csv'
You can access each row as $db[0], $db[1] and each column from your CSV will be a property, e.g. $db[0].Hostname and $db[0].IP
After you have read in your input you just need to select the entry from the array $db. Perhaps like this. However neither your code nor mine covers the case where is no match!
$entry = $db -match $inputID
Then your session will be defined like this
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Scp
HostName = $entry.ip
UserName = "username"
Password = "password"
GiveUpSecurityAndAcceptAnySshHostKey = "true"
}
With all that said, given the error message that you have it would appear that the combination of username/password and ip are not valid.
Add-Type -Path "WinSCPnet.dll"
$db = import-csv 'db.csv'
$inputID = Read-Host -Prompt "Type ID"
$entry = $db -match $inputID
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = $entry.IP
UserName = "username"
Password = "password"
GiveUpSecurityAndAcceptAnySshHostKey = "true"
}
$session = New-Object WinSCP.Session
try {
# Connect
$session.Open($sessionOptions)
# Transfer files
$session.GetFiles("/C:/Program Files/Common Files/logs/Device.log", "E:\loguri\Log\Arhive\*").Check()
}
finally {
$session.Dispose()
}
if (Test-Path "E:\loguri\Log\Arhive\Device.log") {
Compress-Archive -Path "E:\loguri\Log\Arhive\Device.log" -DestinationPath "E:\loguri\Log\Arhive\$inputID.zip" -Update
Remove-Item -Path "E:\loguri\Log\Arhive\Device.log" -Force
}
I am having a lot of trouble getting this code to work in a TS environment.
From a Windows environment, it works great. Just about any variation you will find with a google search of this code works fine in Windows. However in a Task Sequence these variations just produce different error messages for why the computer can't be moved.
Unspecified Error
The specified domain either doesn't exist or couldn't be contacted
Instance of an object not set to an object
I feel that something is happening when we get to the psbase.MoveTo() method call. Up to that point, it can print something out that looks like a reasonable object. In other words, they aren't null or something.
Then psbase.MoveTo() says no.
Example code.
$logFile = "MoveComputerLog.txt"
# Domain Credentials
$account = "domain\osdaccount"
$password = "thepassword"
function logMessage {
param ([string]$logstring)
Write-Host $logstring
Add-content $logFile -value $logstring
}
$computerName = "COMPUTERNAME"
logMessage "computerName: $computerName"
$root = "LDAP://sweet.domain.com"
$domain = New-Object System.DirectoryServices.DirectoryEntry($root, $account, $password)
$search = New-Object System.DirectoryServices.DirectorySearcher($domain)
$search.filter = "(&(objectClass=computer)(name=$computerName))"
$result = $search.findall()
$computerDN = $result.Properties.Item("DistinguishedName")
logMessage "DN: $computerDn"
$computer = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$computerDN", $account, $password)
logMessage "Computer: $computer"
$destination = "LDAP://ou=here,ou=goes,ou=it,dc=sweet,dc=domain,dc=com"
$ou = New-Object System.DirectoryServices.DirectoryEntry($destination, $account, $password)
try {
# "The specified domain couldn't be connected or doesn't exist."
$computer.psbase.MoveTo($ou.Path)
} catch {
Write-Host "Encountered error while moving $computerName"
logMessage $error[0]
}
Here is the definition, ADSI is important:
PS C:\> $computer.psbase.MoveTo
OverloadDefinitions
-------------------
void MoveTo(adsi newParent)
void MoveTo(adsi newParent, string newName)
You can try this, rigth after $result = $search.findall() :
$computer = [ADSI]$result.path
$computer.psbase.Moveto( [ADSI]LDAP://ou=here,ou=goes,ou=it,dc=sweet,dc=domain,dc=com )
So I am trying to create a script that will take a print job from one paused print queue and add it to an active queue. However I am trying to utilize the AddJob() function and upon calling it with or without parameters it returns an exception and I am not sure why. Here is what I have so far
$host.Runspace.ThreadOptions = "ReuseThread"
Add-Type -AssemblyName System.Printing
$permissions = [System.Printing.PrintSystemDesiredAccess]::AdministrateServer
$queueperms = [System.Printing.PrintSystemDesiredAccess]::AdministratePrinter
$server = new-object System.Printing.PrintServer -argumentList $permissions
$queues = $server.GetPrintQueues(#([System.Printing.EnumeratedPrintQueueTypes]::Shared))
foreach ($q in $queues) {
if ($q.IsPaused -eq 1)
{
$qPaused = new-object System.Printing.PrintQueue -argumentList $server,$q.Name,1,$queueperms
}
else
{
$qPlaying = new-object System.Printing.PrintQueue -ArgumentList $server,$q.Name,2,$queueperms
}
}
$byteContents = #('This is a test')
$byteContents | Out-File -FilePath "C:\testinput.txt"
[byte[]]$bytes = Get-Content -Encoding byte -Path "C:\testinput.txt"
#$printJob = $qPaused.GetJob(3).
$qPlaying.AddJob()
$jobStream = $printJob.JobStream
$jobStream | Out-GridView
#$jobStream.Write($bytes, 0, $bytes.Length)
#$jobStream.Close()
What this gives me is an error at the $qPlaying.AddJob() saying
Exception calling "AddJob" with "0" argument(s): "Specified argument was out of the range of valid values.
Parameter name: clientPrintSchemaVersion"
At line:23 char:1
+ $qPlaying.AddJob()
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
Thank you for any feedback.
The version of the Print Schema is defined when you call the constructor for the queue in this line:
$qPlaying = new-object System.Printing.PrintQueue -ArgumentList $server,$q.Name,2,$queueperms
You are using PrintQueue Constructor (PrintServer, String, Int32, PrintSystemDesiredAccess) where the Int32 is the Print Queue Schema version. The MSDN article has a remark that: "The Print Schema version released with Windows Vista is "1"." Which would make sense that when you use 2 and receive an out of range error that 2 isn't an acceptable value.
You could use 1 as the value or use an alternate constructor. For example:
$qPlaying = new-object System.Printing.PrintQueue -ArgumentList $server,$q.Name,$queueperms
I am writing my first Powershell script and coming from C# am confused, my code is below:
function Run(
[string] $command,
[string] $args,
[Ref] [string] $stdout,
[Ref] [string] $stderr
)
{
$p1 = New-Object System.Diagnostics.Process
$p1.StartInfo = New-Object System.Diagnostics.ProcessStartInfo;
$p1.StartInfo.FileName = $command
$p1.StartInfo.Arguments = $arguments
$p1.StartInfo.CreateNoWindow = $true
$p1.StartInfo.RedirectStandardError = $true
$p1.StartInfo.RedirectStandardOutput = $true
$p1.StartInfo.UseShellExecute = $false
$p1.Start()
$p1.WaitForExit()
}
$p = New-Object System.Diagnostics.Process
$p.StartInfo = New-Object System.Diagnostics.ProcessStartInfo;
$p.StartInfo.FileName = "ping"
$p.StartInfo.Arguments = "142.553.22242.2"
$p.StartInfo.CreateNoWindow = $true
$p.StartInfo.RedirectStandardError = $true
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.UseShellExecute = $false
$p.Start()
$p.WaitForExit()
$code = $p.ExitCode
$stderr = $p.StandardError.ReadToEnd()
$stdout = $p.StandardOutput.ReadToEnd()
Run("ping","208.67.222.222","","")
The $p.Start() works, but for some reason the parameters passed in to the Run function are ignored and $p1 fails. What am I doing wrong please?
Exception calling "Start" with "0" argument(s): "The system cannot find the file specified"
At C:\Users\Administrator\Desktop\logtofile.ps1:27 char:5
+ $p1.Start()
+ ~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : Win32Exception
Exception calling "WaitForExit" with "0" argument(s): "No process is associated with this object."
At C:\Users\Administrator\Desktop\logtofile.ps1:28 char:5
+ $p1.WaitForExit()
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException
You have to call run as follows:
Run "ping","208.67.222.222","",""
putting in between the parentheses passes it to the function as a single array argument.
I wasn't trying to start a process from inside a function, but I was getting the same error. It took me a few minutes to realize that it was one of my favorite time-wasters: a UAC trap. I hadn't started PowerShell using "Run as administrator". You have to have admin privileges and run the code as such to start/stop/modify processes that you don't own and this error message is totally unhelpful in this regard.
function Demo {
param (
$fileName,$Arguments
)
$p = New-Object System.Diagnostics.Process
$p.StartInfo = New-Object System.Diagnostics.ProcessStartInfo
$p.StartInfo.FileName = $fileName
$p.StartInfo.RedirectStandardError = $true
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.UseShellExecute = $false
$p.StartInfo.Arguments = $Arguments
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
Write-Host "exit code: " + $p.ExitCode
}
Demo "getmac" " /v"
I got this error with the start() function on a service because a colleague set the service to "disabled" in the Windows Services window. Setting it back to "Manual" fixed it.
I am running in a lab environment and need to automate about 50 machines. I am trying to recover an .xml wireless network profile from a server then install it. This command is being sent from 1 server to the 50 clients.
I recently reimaged my some of my clients and upgraded from PS2 to PS3 and now my Download script is not working anymore.
It does work fine on my PS2 workstations. I am assuming that it might be a permission thing, but I'm not sure. ThrustedHosts is set to * and Script execution policy is set to Unrestricted.
Here's a snippet and the error:
function InstallProfile(){
clear
$fonction =
#'
param($profileName)
$File = "c:\profiles\profile.xml"
$webclient = New-Object System.Net.WebClient
$webclient.Proxy = $NULL
$ftp = "ftp://anonymous:anonymous#192.168.2.200/profiles/$profileName"
$uri = New-Object System.Uri($ftp)
Write-Host (hostname)
$webclient.DownloadFile($uri, $File)
write-host (hostname) (netsh wlan add profile filename="c:\profiles\profile.xml")
'#
$profileName = Read-Host "Enter the profile name(XML file must be present in c:\share\profiles\)"
ExecCmd -fonction $fonction -argument $profileName
func_done
}
#
function ExecCmd
{
param(
$fonction,
$argument
)
$PingTest = RetrieveStatus
$results = #{}
$results = $PingTest.up
$results | sort -uniq | out-Null
$fonctionSB = ConvertTo-ScriptBlock($fonction)
foreach($result in $results)
{
$os = "Windows"
try{
$session = New-PSSession -ComputerName $result.address -Credential $credentials -EA stop
}
catch{
$os = "Not Windows"
}
if($os -eq "Windows"){
Invoke-Command $result.address -ScriptBlock $fonctionSB -Arg $argument -Credential $credentials
Get-PSSession | Remove-PSSession
}
else{
Write-Host $result.address "does not support Powershell commands"
}
}
}
And the error:
Exception calling "DownloadFile" with "2" argument(s): "An exception occurred during a WebClient request."
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
+ PSComputerName : 192.168.2.110
I found a workaround,
I added a try/catch for the webclient.Download, which works for PS2. In the catch portion, I replaced the command with Invoke-WebRequest $uri -OutFile $File
Works fine for PS2 and PS3 this way!