Powershell error/exception handling - powershell

I am having some problems with handling errors/exceptions regarding the invoke-command.
I am trying to catch errors when the target computer does not exist, however the message i am shown and the way the script in the catch block acts makes me think there is something i missed or miss understood.
this is the portion of the script with the problem:
$session = New-Pssession -computername $computerName
Invoke-Command -session $session -ScriptBlock $command -ArgumentList $sqlServerName, $userToGivePermisions
Remove-PSsession -session $session
Basically i want to handle errors when $computerName is not a valid computer on the network. I purposely gave it a wrong name to test it out and i get the following error:
[dcd] Connecting to remote server failed with the following error message : WinRM cannot process the request. The following error occured while using Kerberos authentication: The network path was not found.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does not exist.
-The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [], PSRemotingTransportException
+ FullyQualifiedErrorId : PSSessionOpenFailed
[dcd] is the name of the non existing machine. I put the code in a try catch and did a check on the error message using a -contains. The condition ALWAYS came out false and i tried almost ever single word in the error above.
When i displayed the error message in the catch block using $_.exception.message i got a different error about $session being null.
When i did a -contains using words in the displayed error message about $session it still returned false for every word i tested.
I don't understand which of these is the error and why isn't the -contains ever returning true. I added the -ea stop to all 3 lines to catch all the non terminating errors but to no avail.
Anyone have any idea what is going on?

-contains checks whether an element is in an array or not. e.g:
1,2,3 -contains 2 # Is True
"a","bc","d" -contains "b" # Is False
Try the -match or the -like operators instead. Have a look at the comparison operator documentation.

Related

PowerShell New-GPLink is giving the errors on cross domains

I am trying to write a PowerShell script to link my GPOs to several OUs on multiple domains. The issue I am having is with the New-GPLink cmdlet. When I run the command I get different errors. I can create and link GPOs in all domains in GPMC.
My domain is setup as a Forest with two domains under it (lets call them DomA and DomB). Then I have a third domain not under that forest (lets call it DomC).
My computer is in DomA and my account is in DomC.
The GPO is created in DomA and well call it GPO_Test_1.
The OU I want to link is at ou=Test,ou=GPO Testing,dc=DomA
If I run:
New-GPLink -Name "GPO_Test_1" -Target "ou=Test,ou=GPO Testing,dc=DomA" -LinkEnabled Yes
I get this error:
New-GPLink : The "GPO_Test_1" GPO was not found in the DomC domain.
Parameter name: gpoDisplayName
At line:1 char:1
+ New-GPLink -Name "GPO_Test_1" -Target "ou=Test,ou=GPO Testin ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Microsoft.GroupPolicy.GPDomain:GPDomain) [New-GPLink], ArgumentExceptio
n
+ FullyQualifiedErrorId : GpoWithNameNotFound,Microsoft.GroupPolicy.Commands.NewGPLinkCommand
So I can see its looking at the domain that my account is on. Not the one that my computer is on.
I tried different parameters resulting in different errors.
-Domain DomA
New-GPLink : A referral was returned from the server. (Exception from HRESULT: 0x8007202B)
-Server DConDomA
New-GPLink : Value does not fall within the expected range.
-Domain DomA -Server DConDomA
New-GPLink : Value does not fall within the expected range.
I read that this may be because my credentials are not passing correctly to the other domain. So I tried the below:
Invoke-Command -ComputerName DConDomA -scriptblock {New-GPLink -Name "GPO_Test_1" -Target "ou=Test,ou=GPO Testing,dc=DomA" -LinkEnabled Yes} -credential $c
The "GPO_Test_1" GPO was not found in the DomC domain.
Again the error referencing domain my account is on ...
Adding the -Server DConDomA inside the script block still gives this error.
New-GPLink : Value does not fall within the expected range.
Tried a few different DCs (including RIDMatser on DomA and DomC) but those results in the same type of errors.
I am not sure what I am missing or doing wrong here.
I found my own answer in is Microsoft documentation. Seems I just missed it. My Domain parameter has to be the FQDN where as I using the short name.
https://learn.microsoft.com/en-us/powershell/module/grouppolicy/new-gplink?view=windowsserver2022-ps
-Domain
Specifies the domain for this cmdlet. You must specify the fully qualified domain name (FQDN) of the domain.
This note explained why it was checking the domain where my account was as well.
"If you do not specify the Domain parameter, the domain of the user that is running the current session is used. If the cmdlet is being run from a computer startup or shutdown script, the domain of the computer is used. For more information, see the Notes section in the full Help."

Passing active powershell Session to background jobs

I am writing a powershell script to manipulate Exchange Online mailboxes.
I want this script to run with background jobs in parallel, so I'm trying to use PoshRSJobs (https://github.com/proxb/PoshRSJob) to create the jobs.
My code is:
Connect-ExchangeOnline -Credentials ...
Start-RSJob -ModulesToImport ExchangeOnlineManagement -Throttle $ProcesosConcurrentes -InputObject $jobs -ScriptBlock {
./migra_buzon.ps1 ...
}
Where:
$jobs is an arraylist where I have the parameter of the mailboxes I want to operate with
migra_buzon.ps1 is another powershell scripts that operates over one specified mailbox
The problem I have when I run this way is that in the jobs I have the error:
The term 'Add-MailboxPermission' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Although other commands like Get-EXOMailbox are working correctly.
Looking for help I found that the problem can be related with the session, so I changed my code to:
Connect-ExchangeOnline -Credentials ...
Start-RSJob -ModulesToImport ExchangeOnlineManagement -Throttle $ProcesosConcurrentes -InputObject $jobs -ScriptBlock {
$o365session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid" -Credential $(Import-Clixml $Using:ExchangeCredentials) -Authentication "Basic" -AllowRedirection
Import-PSSession $o365Session -CommandName #('Add-MailboxPermission', 'Get-MailboxPermission')
./migra_buzon.ps1 ...
}
In this case, the problem I have is with the Exchange connection. After running a few jobs I'm getting the error:
[outlook.office365.com] Processing data from remote server outlook.office365.com failed with the following error message: Client did not get proper response from server. For more information, see the about_Remote_Troubleshooting Help topic.
Cannot validate argument on parameter 'Session'. The argument is null. Provide a valid value for the argument, and then try running the command again.
So my question is, what is the right way to run background jobs sharing the connection got in the main process?
Thanks
PS: I first tried to run jobs with Start-Job, but with this the problem is that each background job needs its own connection, so I got and maximum number of connections exceeded. And this is the reason I changed my code to Start-RSJob
It appears that you are hitting Exchange Online throttling limits.
If that indeed the case, you can try the following method.
How to relax PowerShell throttling
There is a relatively new customer facing way to increase or update PowerShell Throttling Policies.
Go to Microsoft 365 admin center.
Validate that you are logged in with the user that has the correct role assignment.
Click on the Need Help? Widget in the bottom right corner
Graphical user interface
Type Exchange PowerShell throttling in the search box and select “Temporarily update throttling policies for a migration”. Keep in mind that this is only applicable for 90 days. After 90 days, the throttles will return to back to the default values for that tenant.
MachSol offers Tenant management using a job engine, that allows you to do multiple operations using front-end and let the jobs handler take care of processing in background. You can give it a try:
https://www.machsol.com/machpanel-automation-for-microsoft-CSP-partners/

Powershell script to move file from one location to another then display message box to a different computer on our network

I am having an issue with this Powershell script. I am completely new to powershell. I am trying to automate a specific process. I am attempting to create a script that can take an image, move it to another folder on another drive, then send a message box to a different computer on the domain letting the user know the file transfer has been completed. I was able to get the script to move the file from one location to another the works correctly. I was able to display a message box as well but when I try to add an image to the message box I get the following error below. Also, I have no idea how to send this messagebox to a different computer other than the one the script is running on. Help please.
Cannot convert argument "icon", with value:
"C:\Users\austin.holmes\Downloads\botpic.jpg", for "Show" to type
"System.Windows.MessageBoxImage": "Cannot convert value
"C:\Users\austin.holmes\Downloads\botpic.jpg" to type
"System.Windows.MessageBoxImage". Error: "Unable to match the
identifier name C:\Users\austin.holmes\Downloads\botpic.jpg to a
valid enumerator name. Specify one of the following enumerator names
and try again: None, Hand, Error, Stop, Question, Exclamation,
Warning, Asterisk, Information"" At line:9 char:1+
[System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)
CategoryInfo : NotSpecified: (:) [], MethodException
FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
CODE:
$_SourcePath = "C:\dummy.txt"
$_DestinationPath = "D:\"
Copy-item –path $_SourcePath –destination $_DestinationPath
$msgButton = [System.Windows.MessageBoxButton]::OK
$msgTitle = “Little Sis Sync Agent Bot!”
$msgbody = “Little Sis Sync Agent files have been moved. Thank me later. :]”
$msgImage = 'C:\Users\austin.holmes\Downloads\botpic.jpg'
[System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)
I tried the Invoke-Command and I get the follwing error
$_SourcePath = "C:\Users\austin.holmes\Desktop\dummy.txt"
$_DestinationPath = "C:\"
Copy-item –path $_SourcePath –destination $_DestinationPath
Invoke-Command -ComputerName AHC-L80316-AH -ScriptBlock{
$msgButton = [System.Windows.MessageBoxButton]::'OK'
$msgTitle = “Little Sis Sync Agent Bot!”
$msgbody = “Little Sis Sync Agent files have been moved!”
$msgImage = 'Warning'
[System.Windows.MessageBox]::Show($msgBody,$msgTitle,$msgButton,$msgImage)}
[AHC-L80316-AH] Connecting to remote server AHC-L80316-AH failed with
the following error message : The client cannot connect to the
destination specified in the request. Verify that the service on the
destination is running and is accepting requests. Consult the logs
and documentation for the WS-Management service running on the
destination, most commonly IIS or WinRM. If the destination is the
WinRM service, run the following command on the destination to
analyze and configure the WinRM service: "winrm quickconfig". For
more information, see the about_Remote_Troubleshooting Help topic.
In a MessageBox you can only display one of the available icons in the MessageBoxImage-enumerator. As the errormessage says, use None, Hand, Error, Stop, Question, Exclamation, Warning, Asterisk or Information
To show your own images, you will have to created a separate form.
To run code on a remote computer (in this case your own), use Invoke-Command with computername and scriptblock as parameters. Take a lock at The following link:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-7

Get-WinEvent via Powershell remoting

I have a non-admin access to a server. I'm allowed to connect via RDP, and to use PowerShell remoting. When I invoke the following PowerShell command from an RDP session:
Get-WinEvent -MaxEvents 100 -Provider Microsoft-Windows-TaskScheduler
I get 100 records, as expected.
When I do the same via PowerShell remoting, by invoking the following from my local machine:
invoke-command -ComputerName myserver {Get-WinEvent -MaxEvents 100 -Provider Microsoft-Windows-TaskScheduler }
I get an error:
No events were found that match the specified selection criteria.
CategoryInfo : ObjectNotFound: (:) [Get-WinEvent], Exception
FullyQualifiedErrorId : NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand
Any idea why? The remote PowerShell session should be running under identical credentials, right?
EDIT: whoami does show a difference in the security context between RDP logon and PowerShell remoting - the group set is different. In the RDP logon session, there are the following groups in the token:
BUILTIN\Remote Desktop Users
NT AUTHORITY\REMOTE INTERACTIVE LOGON
while in the remoted one, there's
CONSOLE LOGON
That could account for the discrepancy in rights...
EDIT: from the registry, it looks like the task scheduler log somehow is a part of the System log. According to MS KB article Q323076, the security descriptor for the System log can be found under HKLM\SYSTEM\CurrentControlSet\Services\EventLog\System, value CustomSD. I can't check the server in question, but on another server where I'm an admin, there's no CustomSD under that key. Under HKLM\SYSTEM\CurrentControlSet\Services\EventLog\System\Microsoft-Windows-TaskScheduler, neither. Only the Security log gets a CustomSD. The next question is, where's the default SD?
Permissions on the actual log file at C:\Windows\System32\winevt\LogsMicrosoft-Windows-TaskScheduler%4Operational.evtx are irrelevant, the access is being mediated by the EventLog service anyway.
If you are not an administrator on the remote computer, and invoke-command -ComputerName myserver {whoami /all} tells you are who you expected to be.
You will need to be part of Event Log Reader group on the remote computer.
As well as Remote Management Users group, which I believe you already are.
If you need to read security logs, you will also need Manage auditing and security log under Local Security Policy -> Security Settings -> Local Policies -> User Rights Assignment
According to Default ACLs on Windows Event Logs # MSDN blog, in Windows Server 2003+, the default ACL for the System log goes:
O:BAG:SYD:
*(D;;0xf0007;;;AN) // (Deny) Anonymous:All Access
*(D;;0xf0007;;;BG) // (Deny) Guests:All Access
(A;;0xf0007;;;SY) // LocalSystem:Full
(A;;0x7;;;BA) // Administrators:Read,Write,Clear
(A;;0x5;;;SO) // Server Operators:Read,Clear
(A;;0x1;;;IU) // INTERACTIVE LOGON:Read <===================
(A;;0x1;;;SU) // SERVICES LOGON:Read
(A;;0x1;;;S-1-5-3) // BATCH LOGON:Read
(A;;0x2;;;LS) // LocalService:Write
(A;;0x2;;;NS) // NetworkService:Write
Does NT AUTHORITY\INTERACTIVE LOGON include RDP logon? I've found a forum message that says so, but I'd better find a doc to that effect...
The article claims this ACE comes "straight from the source code". So it's hard-coded in the service, with a chance to change via the registry.
You need local admin rights to open a powershell session.
But there is a workaround/alterative here:
https://4sysops.com/archives/powershell-remoting-without-administrator-rights/
I had the weirdest variation of this problem, was driving me nuts !
Remoting from a server W2008r2 (logged on as domain admin, inside interactive powershell session) to workstation Win7 to get logon/logoff events :
invoke-command -computername $pc {Get-WinEvent -FilterHashtable #{logname='
Security';Id=#(4624,4634)}}
-> No events were found that match the specified selection criteria.
But it does work when outputting an empty string in the scriptblock before the Get-Winevent :
invoke-command -computername $pc {"";Get-WinEvent -FilterHashtable #{lognam
e='Security';Id=#(4624,4634)}}
TimeCreated ProviderName Id Message PSComputerName
----------- ------------ -- ------- --------------
19/03/2018 11:51:41 Microsoft-Windows-Se... 4624 An account was succe... b25_x64
19/03/2018 11:51:41 Microsoft-Windows-Se... 4624 An account was succe... b25_x64
Stumbled upon this fix after trying everything: Enter-Pssession, New-Pssession, using -credential parameter to pass a predefined credential to invoke-command, to get-winevent, to both. Nothing worked, gave "No events..." in every combination.
Then I inserted a $cred inside the scriptblock to show the passed on credential for debugging, and suddenly I got the events I was looking for...

Grabbing system product keys

So I'm trying to use the PS script found at http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97#content to pull Windows product keys from my domain remotely. However, when it hits a host it returns Exception calling “OpenRemoteBaseKey” with “2″ argument(s): “The network path was not found” instead of the product key. It should also be noted that this works locally. After poking around at the internals of the script, it seems like the offending line is
$remoteReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer)
Research (because I'm totally new to PoSH) indicates that this type of error gets thrown when remote registry access isn't working. Trying to hook into the registry on my test target via regedit shows that I need to have Windows Firewall: Allow inbound remote administration exception set to enabled in Group Policy. I set it and then pulled the updated policy down to the same result. What other stuff might be getting in the way of my connection?
I would recommend using PSRemoting over using the remote registry. Assuming this is set up, all you would have to do is:
$computers = #('localhost')#list of computers
#unless you are currently logged in as a domain admin
# you will need to provide credentials
$cred = Get-Credential domain\administrator
Invoke-Command -Credential $cred -ComputerName $computers -ScriptBlock {
function Get-ProductKey{
#from http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97
}
get-ProductKey
}| ft Computername,OSDescription,OSVersion,ProductKey
This will print out the following output:
Computername OSDescription OSVersion ProductKey
------------ ------------- --------- ----------
%name% Microsoft Windows 8 Pro 6.2.9200 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
I used the following command through powershell, ran it as admin:
wmic /user:jc1_admin /node:pc00202 os get "SerialNumber"