If not run after get-service in powershell - powershell

I'm trying to access the service status of the remote server. i wrote this
$ServerList = get-content -Path "c:\users\cont015\Desktop\ServerList.txt"
ForEach ($ServerName in $ServerList)
{
$Status= Get-Service -ComputerName $ServerName | ?{$_.DisplayName -like "SQL Server (*"} | select Status | format-wide
if($st -eq "Running")
{
$SeverName
$Status
}
else
{
}
}
it is showing
$Status= Get-Service -ComputerName $ServerName | ?{$_.DisplayName -li ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Service], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetServiceCommand
in error. i don't know what i am missing. but when i run without if condition if shows proper output.

$ServerList = Get-Content -Path "c:\users\cont015\Desktop\ServerList.txt"
ForEach ($ServerName in $ServerList)
{
$Status= #(
Get-Service -ComputerName $ServerName -DisplayName "SQL Server (*" |
Select-Object -ExpandProperty Status)
if ("Running" -in $Status)
{
[PSCustomObject]#{
Server = $ServerName
Status = $Status
}
}
else
{
}
}
Explanation:
Get-Service docs: -DisplayName
Specifies, as a string array, the display names of services to be retrieved. Wildcards are permitted (used instead of Where-Object as such filtering is always faster).
Array subexpression operator #( ). -
Returns the result of one or more statements as an array. The result is always an array of 0 or more objects (i.e. force Powershell to always return an array when a call returns only one object or even $null)
Used [PSCustomObject]#{} in output instead of a sequence of strings (learn advantages at Everything you wanted to know about PSCustomObject).

Related

PowerShell write file to local machine when using invoke-command

I am running invoke-command on 50 servers and I need to write multiple files to the local machine. I have tried using a combination of UNC paths out-file and write-output, but cant get it to write the files to the local machine.
$data = Invoke-Command -ComputerName $servers -ScriptBlock {
$Server = $env:COMPUTERNAME
$services = Get-Service | Where-Object { $_.Status -ne "Running" } | Select-Object name
$services | Write-Output "\\local\monitor\Services\$Server.html"
$EventLogs = Get-WinEvent -FilterHashtable #{Logname = 'Application'; Level = 1; StartTime = [datetime]::Now.AddMinutes(-15) }
$EventLogs | Out-File "\\local\monitor\Events\$server.html"
}
Edit:
If I run this on the remote server, It will write the file to the local server
$services | Write-Output "\\local\monitor\Services\file.txt"
However, I get access denied running this - I am running PS as admin. Why Access Denied when running invoke-command, but not directly from remote server?
Invoke-Command -ComputerName $remote -ScriptBlock {
"this is a test" | Out-File -FilePath "\\local\monitor\Services\file.txt" -force
$Error
}
Out-File : Access to the path '\\local\monitor\Services\file.txt' is denied.
At line:3 char:20
+ ... s a test" | Out-File -FilePath "\\local\monitor\Services\file.txt" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], UnauthorizedAccessException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Try this...
Invoke-Command -ComputerName $Servers -ScriptBlock {
$Server = $env:COMPUTERNAME
$services = Get-Service |
Where-Object { $PSItem.Status -ne 'Running' } |
Select-Object name |
Out-File -LiteralPath "\\local\monitor\Services\$Server.html" -Append
$EventLogs = Get-WinEvent -FilterHashtable #{
Logname = 'Application'
Level = 1
StartTime = [datetime]::Now.AddMinutes(-15)
} |
Out-File -LiteralPath "\\local\monitor\Events\$server.html" -Append
}

Get local profile list with powershell

I'm on a Windows server 2008 R2 and I need an extract of the local profile list, so I use Powershell to look into the registry and get what I want :
$path = 'Registry::HKey_Local_Machine\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\*'
$items = Get-ItemProperty -path $path
Foreach ($item in $items) {
$objUser = New-Object
System.Security.Principal.SecurityIdentifier($item.PSChildName)
$objName = $objUser.Translate([System.Security.Principal.NTAccount])
$item.PSChildName = $objName.value
}
echo $items | Select-Object -Property PSChildName | Export-Csv
C:\scripts\PSScripts\UserProfile.csv -Encoding UTF8
It worked with another machine using Windows Server 2012 R2 but here I got a lot of errors, but always the same one :
Exception calling "Translate" with "1" argument(s): "Some or all
identity references could not be translated." At
C:\scripts\PSScripts\users_profile.ps1:5 char:34
+ $objName = $objUser.Translate <<<< ([System.Security.Principal.NTAccount])
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
The .csv file is created but with issues, like a profile shown more than one time, like this :
DOMAIN\User1
DOMAIN\User2
DOMAIN\User3
DOMAIN\User3
DOMAIN\User4
DOMAIN\User5
DOMAIN\User5
DOMAIN\User5
DOMAIN\User6
Is there a difference between WS2008 and WS2012 which can cause this problem? Or is it something else?
I'd suggest using WMI to be consistent across platforms plus some error handling:
$path = 'C:\scripts\PSScripts\UserProfile.csv'
Get-CimInstance -ClassName Win32_UserProfile -Filter Special=FALSE -PipelineVariable user |
ForEach-Object -Begin {$ErrorActionPreference = 'Stop'} {
try
{
$id = [System.Security.Principal.SecurityIdentifier]::new($user.SID)
$id.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
Write-Warning -Message "Failed to translate $($user.SID)! $PSItem"
}
} |
Select-Object -Property #{Label='PSChildName'; Expression={$PSItem}} |
Export-Csv -Path $path -Encoding ascii -NoTypeInformation
PSv2 solution:
Get-WmiObject -Class Win32_UserProfile -Filter Special=FALSE |
ForEach-Object -Begin {$ErrorActionPreference = 'Stop'} {
try
{
$sid = $_.SID
$id = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $sid
$id.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
Write-Host "Failed to translate $sid! $_" -ForegroundColor Red
}
} |
Select-Object -Property #{Label='PSChildName'; Expression={$_}} |
Export-Csv -Path $path -Encoding ascii -NoTypeInformation

Powershell Script reading file into array

I have a script I'm working on. I want it to read in a column named ComputerName and one named UserName.
My CSV file looks like this:
ComputerName | Username
computer01 | user1
computer02 | user2
The Pipes are representing cells in excel.
Here's my script:
$computerName = #()
$userName = #()
Import-Csv C:\test\script\Computername_username_test.csv -Delimiter "|" |`
ForEach-Object
{
$computerName += $_.ComputerName
$userName += $_.UserName
}
$destination = New-Item -ItemType Directory -Path C:\test\$userName\dictionary_Files\ -force
$fileList = Get-WmiObject -Class CIM_DataFile -Filter "Drive='C:' And Extension='dic'" -Computername $computerName
foreach ($file in $fileList)
{
$drive, $path = $file.Name.Split('\',2)
$drive = $drive -replace ':','$'
$remoteFile = "\\$computerName\$drive\$path"
Write-Verbose "Copy $remoteFile to $destination"
Copy-Item $remoteFile -Destination $destination -Confirm
}
My goal is to search the C drive of the remote computer for all files with the .dic extension and copy them to a location inside a folder that is named the same as their username from the excel sheet.
When I run this I'm getting the following:
PS C:\Test\Script> C:\Test\Script\DicFiles03_importCSV.ps1
cmdlet ForEach-Object at command pipeline position 2
Supply values for the following parameters:
Process[0]:
$computerName += $_.ComputerName
$userName += $_.UserName
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'. The argument is null, empty, or an element of the argument
collection contains a null value. Supply a collection that does not contain any null values and then try the command again.
At C:\Test\Script\DicFiles03_importCSV.ps1:13 char:102
+ ... -Filter "Drive='C:' And Extension='dic'" -Computername $computerName
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Thank you for your help.
I'm think its because you have your { after the foreach-object on the next line powershell is a scripting language so its particular about line endings.

Why am I getting a Critical Error when creating a WMI Instance?

I have a script that is intended to create instances of a custom WMI class based on an ACL output converted to a string. This is ultimately to query permissions via that WMI class.
The meat of the process is:
[cmdletbinding()]
param([Parameter(ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]$Computer = '.')
$shares = gwmi -Class win32_share -ComputerName $computer | select -ExpandProperty Name
foreach ($share in $shares) {
$acl = $null
#Write-Host $share -ForegroundColor Green
#Write-Host $('-' * $share.Length) -ForegroundColor Green
$objShareSec = Get-WMIObject -Class Win32_LogicalShareSecuritySetting -Filter "name='$Share'" -ComputerName $computer
try {
$SD = $objShareSec.GetSecurityDescriptor().Descriptor
foreach($ace in $SD.DACL){
$UserName = $ace.Trustee.Name
If ($ace.Trustee.Domain -ne $Null) {$UserName = "$($ace.Trustee.Domain)\$UserName"}
If ($ace.Trustee.Name -eq $Null) {$UserName = $ace.Trustee.SIDString }
[Array]$ACL += New-Object Security.AccessControl.FileSystemAccessRule($UserName, $ace.AccessMask, $ace.AceType)
for( $i = 1; $i -lt $ACL.Length; $i++)
{
$permission = $ACL[$i] | Out-String
Write-Host "permission for $share is $permission"
Set-WmiInstance -Class TestShare -Puttype CreateOnly -Argument #{Name = $share; Permissions = $permission}
}
} #end foreach ACE
} # end try
catch
{
Write-host "Failed to create or update instance for share $share"
Write-Host ""
}
#$ACL
# Write-Host $('=' * 50)
} # end foreach $share
Which returns the below error:
Set-WmiInstance : Critical error
At ...\GetShares.ps1:35 char:15
+ ... Set-WmiInstance -Class LDLocalShare -Puttype CreateOnly - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Set-WmiInstance], ManagementException
+ FullyQualifiedErrorId : SetWMIManagementException,Microsoft.PowerShell.Commands.SetWmiInstance
There seems to be an issue with the way I'm converting Security.AccessControl.FileSystemAccessRule to a string, because using the code below and providing literal strings creates an instance without issue, with the appropriate values:
Set-WmiInstance -Class TestShare -Puttype CreateOnly -Argument #{Name = "TestShare" ; Permissions = "TestPermission"}
I've looked around on technet forum posts related to the error returned, but the issue always seems to be with trying to create an instance of a class that wasn't created. The class is definitely there. Is there some way to convert Security.AccessControl.FileSystemAccessRule without running into this, or a different way to store that information in an instance of a custom WMI class?
Edit: Example output of $permission, which gets converted to a string
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : Everyone
IsInherited : False
InheritanceFlags : None
PropagationFlags : None
To create object ,you can do this by running the below snippet once as administrator :
$WMI_Class = ""
$WMI_Class = New-Object System.Management.ManagementClass("Root\cimv2", $null, $null)
$WMI_Class.name = 'TestShare'
$WMI_Class.Properties.Add("Name", [System.Management.CimType]::String, $false)
$WMI_Class.Properties["Name"].Qualifiers.Add("key", $true)
$WMI_Class.Properties.Add("Permissions", [System.Management.CimType]::String, $false)
$WMI_Class.Put()
you can test this by creating a dummy object (also should be run as admin):
Set-WmiInstance -Class TestShare -Puttype CreateOnly -Argument #{Name = 'test';Permissions = 'x'}
Then your code should work fine with this small change for set-wmiinstance:
Set-WmiInstance -Class TestShare -Puttype CreateOnly -Argument #{Name = $share;Permissions = $permission.Replace("`r`n","`n")}
but ,I have defined share name as key and properties does not have write qualifier .So you won't be able to modify the object later for the same share

Getting a specific service recovery option for a list of servers

Apologies in advance for errors. I'm still learning Powershell.
I'm trying to check a specific service recovery options for a list of servers in AD
$credential = Get-Credential
$servers = Get-ADComputer -Filter * -properties * | ?{$_.OperatingSystem -match "server"} | ft name -hidetableheaders | out-string
$Results = #()
foreach ($Server in $Servers)
{
Invoke-command -cn $server -credential $credential -ScriptBlock {Get-WMIObject win32_service |
Where-Object {$_.description -imatch "nscli" -and $_.startmode -eq "Auto"}; foreach ($service in $services){sc.exe qfailure $service.name}}
}
I'm getting the following error
Invoke-command : One or more computer names are not valid. If you are trying to pass a URI, use the -ConnectionUri parameter, or pass URI objects
instead of strings.
At line:1 char:32
+ foreach ($Server in $Servers) {Invoke-command -cn $server -credential $credentia ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
If I run the command directly on each server, I don't have any issues.
Invoke-command -cn EXCHANGE -credential $credential -ScriptBlock {$services = Get-WMIObject win32_service | Where-Object {$_.description -imatch "nscli" -and $_.startmode -eq "Auto"}; foreach ($service in $services){sc.exe qfailure $service.name}}
[SC] QueryServiceConfig2 SUCCESS
SERVICE_NAME: NSClientpp
RESET_PERIOD (in seconds) : 0
REBOOT_MESSAGE :
COMMAND_LINE :
FAILURE_ACTIONS : RESTART -- Delay = 120000 milliseconds.
RESTART -- Delay = 120000 milliseconds.
Because I'm using sc.exe, I'm unsure how to output the list into a csv format but at least, I can get some information of which servers the service failure restart aren't set accordingly
Thanks in advance
Cheers
G
Since Invoke-Command doesn't support the -WhatIf switch, your best bet is to echo the server name on console to see the server name that causes failure. In the debugging statement, the server name is enclosed withing single quotes ' for, say, extra whitespace is easier to see. Like so,
foreach ($Server in $Servers)
{
Write-host $("Now processing server '{0}' " -f $Server)
Invoke-command ...
}
You could also try to write the Invoke-Command statements to console and copy-paste those to another a Powershell session to see which, if any, is the failing one.
For what it is worth, you seem to use variables $Server and $server (note the upper/lowercase difference). Though variable names are not case sensitive in Powershell, you might have uninitialized variables caused by simple typos. To guard against such, use Set-StrictMode. It will cause Powershell to complain about uninitialized variables, which commonly are caused by mistyping variable names.
Got it working. Should have responded earlier. Thanks guys.
# Get the credential
$Credential=Get-Credential
# Collect the server list
$Servers = Get-ADComputer -Filter * -Properties operatingsystem | Where operatingsystem -match 'server'
$Results = #()
## Check service status
$Results = foreach ($Server in $Servers)
{Invoke-Command -ComputerName $Server.Name –Ea 0 -Credential $Credential {Get-Service |?{$_.DisplayName –match “nscli”} }}
## Create a csv report
$Results| Sort PSComputerName | select PSComputerName, DisplayName, Name, Status |Export-Csv nsclient_service.csv -NoTypeInformation -UseCulture
# Check the recovery options for NSclient service on each Server
foreach ($Server in $Servers)
{ write-host "Checking " $Server.Name;
Invoke-Command -ComputerName $Server.Name –Ea 0 -Credential $Credential `
{$services = Get-WMIObject win32_service | Where-Object {$_.name -imatch "nscli" -and $_.startmode -eq "Auto"}; `
foreach ($service in $services){sc.exe qfailure $service.name}}
}