Background:
we created a script was watch our timestamp of the files and when it detect a file that last longer as 10 min in the hotfolder, the script automaticly restart the service.
Thats actually the powershell working powershell script:
#Variablen ausfüllen
$watchfolder = '\\dcsrv\public\Scanner-Eingang'#UNC Pfade funktionieren
$CurTimeStamp = Get-Date
$FileAge = 10 #in Minuten
#Er prüft die Zeit der Dokumente
$Files = Get-ChildItem -Path $watchfolder | Where-Object{($_.LastWriteTime -le
$CurTimeStamp.AddMinutes(-1 * $FileAge))}
#Für jedes Dokument
ForEach ($File in $Files) {
Write-Host " " $File " - " $File.LastWriteTime
## Damit wir der Dienst neugestartet
Restart-Service -Name Spooler
## Sobald er eine Datei gefunden hat stopt er
break
}
The service is running on a server out of the domain and need to reach the hotfolders. The hotfolders are on a domaincontroller with other credentials.
Now i need to connect in my powershell script with the right credentials, some examples i tried you can see here:
#Variablen ausfüllen
$watchfolder = '\\dcsrv\public\Scanner-Eingang'#UNC Pfade funktionieren
$CurTimeStamp = Get-Date
$username = 'user'
$password = '1234'
$FileAge = 10 #in Minuten
#Er prüft die Zeit der Dokumente
$Files = Get-ChildItem -Path $watchfolder $username $password | Where-Object{($_.LastWriteTime -le
$CurTimeStamp.AddMinutes(-1 * $FileAge))}
#Für jedes Dokument
ForEach ($File in $Files) {
Write-Host " " $File " - " $File.LastWriteTime
## Damit wir der Dienst neugestartet
Restart-Service -Name Spooler
## Sobald er eine Datei gefunden hat stopt er
break
}
didnt worked then i tried something else
#Variablen ausfüllen
$watchfolder = '\\dcsrv\public\Scanner-Eingang'#UNC Pfade funktionieren
$CurTimeStamp = Get-Date
$FileAge = 10 #in Minuten
#Er prüft die Zeit der Dokumente
$Files = Get-ChildItem -Path $watchfolder /user:user password:1234 | Where-Object{($_.LastWriteTime -
le $CurTimeStamp.AddMinutes(-1 * $FileAge))}
#Für jedes Dokument
ForEach ($File in $Files) {
Write-Host " " $File " - " $File.LastWriteTime
## Damit wir der Dienst neugestartet
Restart-Service -Name Spooler
## Sobald er eine Datei gefunden hat stopt er
break
}
also without success
Now i hope somebody can help me.
Thanks you!
I think the main question is how do you authenticate to the remote domain, in order to watch the file share. Get-ChildItem doesn't have a -credential parameter.
You can try creating a mapped drive or path first, but you'll need to establish a credential object to use with the New-PSDrive command.
$Pwd = ConvertTo-SecureString -String "password" -AsPlainText -Force
$Cred = [System.Management.Automation.PSCredential]::New('UserName', $pwd)
New-PSDrive -Root '\\dcsrv\public\Scanner-Eingang' -PSProvider FileSystem -Name "ShareToMonitor" -Credential $Cred
...
Note For Powershell 4.0, change:
$Cred = [System.Management.Automation.PSCredential]::New('UserName', $pwd)
to:
$Cred = New-Object System.Management.Automation.PsCredential('UserName',$Pwd)
You can read about New-PSDrive here.
However, it's usually a bad idea to write a password directly into a script. You can store it securely in a file
There are many guides and/or blog articles on the Internet to help with that. Here's the first Google result. Once you establish the secure file you'll have to add code to the script to retrieve it. Then use it to create the credential object as demonstrated above.
Note: The file can only be decoded on the computer and under the account from which it was created.
Related
Im wanting to add a printer and its port to the print server only if either that printer name and printer port isn't already taken.
I have this so far
$prnt = Import-Csv C:\scripts\printer.csv
foreach ($printer in $prnt) {
$var = Get-Printer
If (($var.name -contains $printer.Printername) -and ($var.portname -contains
$printer.IPAddress))
{
Write-Host "$printer exist!" -ForegroundColor Blue
}
else
{
Add-PrinterPort -ComputerName Printsrv01 -Name $printer.IPAddress -
PrinterHostAddress $printer.IPAddress
Add-Printer -ComputerName Printsrv01 -Name $printer.Printername -
DriverName $printer.Driver -PortName $printer.IPAddress -Location
$printer.Location
}
}
Problem is mainly with my 'if' statement. It catches the printer name but not the portnumber/ip. (The portnumber is the ip). And I also think my if statement is comparing the whole array of values from the csv file, and not just the specific value in the array like I want. Any help would be appreciated.
Csv file is setup like this
enter image description here
Try this:
$prnt = Import-Csv C:\scripts\printer.csv
$printers = (Get-Printer).Name
$ports = (Get-PrinterPort).PrinterHostAddress
foreach ($printer in $prnt)
{
If (($printers -contains $printer.Printername) -or ($ports -contains $printer.IPAddress))
{
Write-Host "$printer exist!" -ForegroundColor Blue
}
else
{
Add-PrinterPort -ComputerName Printsrv01 -Name $printer.IPAddress -PrinterHostAddress $printer.IPAddress
Add-Printer -ComputerName Printsrv01 -Name $printer.Printername -DriverName $printer.Driver -PortName $printer.IPAddress -Location $printer.Location
}
}
I am trying to run a perl script whenever there is a service crash. The perl script intends to restart the service and send a mail to all the developers.
I have used windows recovery options for that, where it has an option to run a program . I have filled the required details in the command line option but the script doesn't seem to get executed. Can you please help me by sharing your knowledge on this?
Recovery tab configuration
I have tried with Restart service option and that is working fine but the run a program isn't executing the script. Am I missing something?
Any comment on this will be helpful.
I recently implemented a recovery option to run a powershell script that attempts to restart the service a defined number of times and sends an email notification at the conclusion, it also attaches a txt file with recent relevant logs.
After several attempts (and despite all the other things I have seen) The configuration of fields on the recovery tab in services is as follows:
Program: Powershell.exe
**Not C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe
Command line parameters: -command "& {SomePath\YourScript.ps1 '$args[0]' '$args[1]' '$args[n]'}"
eg: -command "& {C:\PowershellScripts\ServicesRecovery.ps1 'Service Name'}"
**The $args are parameters that will be passed to your script. These are not required.
here is the powershell script:
cd $PSScriptRoot
$n = $args[0]
function CreateLogFile {
$events = Get-EventLog -LogName Application -Source SomeSource -Newest 40
if (!(Test-Path "c:\temp")) {
New-Item -Path "c:\temp" -Type directory}
if (!(Test-Path "c:\temp\ServicesLogs.txt")) {
New-Item -Path "c:\temp" -Type File -Name "ServicesLogs.txt"}
$events | Out-File -width 600 c:\temp\ServicesLogs.txt
}
function SendEmail {
$EmailServer = "SMTP Server"
$ToAddress = "Name#domain.com"
$FromAddress = "Name#domain.com"
CreateLogFile
$Retrycount = $Retrycount + 1
send-mailmessage -SmtpServer $EmailServer -Priority High -To $ToAddress -From $FromAddress -Subject "$n Service failure" `
-Body "The $n service on server $env:COMPUTERNAME has stopped and was unable to be restarted after $Retrycount attempts." -Attachments c:\temp\ServicesLogs.txt
Remove-Item "c:\temp\ServicesLogs.txt"
}
function SendEmailFail {
$EmailServer = "SMTP Server"
$ToAddress = "Name#domain.com"
$FromAddress = "Name#domain.com"
CreateLogFile
$Retrycount = $Retrycount + 1
send-mailmessage -SmtpServer $EmailServer -Priority High -To $ToAddress -From $FromAddress -Subject "$n Service Restarted" `
-Body "The $n service on server $env:COMPUTERNAME stopped and was successfully restarted after $Retrycount attempts. The relevant system logs are attached." -Attachments c:\temp\ServicesLogs.txt
Remove-Item "c:\temp\ServicesLogs.txt"
}
function StartService {
$Stoploop = $false
do {
if ($Retrycount -gt 3){
$Stoploop = $true
SendEmail
Break
}
$i = Get-WmiObject win32_service | ?{$_.Name -imatch $n} | select Name, State, StartMode
if ($i.State -ne "Running" -and $i.StartMode -ne "Disabled") {
sc.exe start $n
Start-Sleep -Seconds 35
$i = Get-WmiObject win32_service | ?{$_.Name -imatch $n} | select State
if ($i.state -eq "Running"){
$Stoploop = $true
SendEmailFail}
else {$Retrycount = $Retrycount + 1}
}
}
While ($Stoploop -eq $false)
}
[int]$Retrycount = "0"
StartService
I'm trying to modify the share permissions of share drives on a bunch of windows servers which are running either 2008 R2 or 2012.
I worked up a script which you can find here:
Import-Module ActiveDirectory
$list = Get-ADComputer -Filter 'SamAccountName -like "*FP*"' | Select -Exp Name
foreach ($Computer in $list)
{
Grant-SmbShareAccess -Name User -CimSession Server -AccountName "username" -AccessRight Full -confirm:$false
$acl = (Get-Item \\$Computer\d$\User ).GetAccessControl('Access')
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule ("Corp\uc4serv","FullControl","ContainerInherit, ObjectInherit","None","Allow")
$acl.AddAccessRule($rule)
Set-Acl \\$Computer\d$\User $acl
Write-Host -ForegroundColor DarkGreen "Permissions granted on $Computer"
}
Write-Host -ForegroundColor DarkBlue "Command Has Completed"
But it doesn't work on 2008 servers presumably because they can't run the Get-SmbShareAccess cmdlet.
What I'm trying to do is very similar to this post here: How to set share permissions on a remote share with Powershell? but specifically on Windows servers.
I also found this code on a website (http://windowsitpro.com/powershell/managing-file-shares-windows-powershell):
$acl = Get-Acl `
\\servername\c$\Users\username\sharetest
$permission = "corp\uc4serv","FullControl","Allow"
$accessRule = New-Object `
System.Security.AccessControl.FileSystemAccessRule `
$permission
$acl.SetAccessRule($accessRule)
$acl |
Set-Acl \\servername\c$\Users\username\sharetest
But this just sets the Security on the share instead of the share permissions.
I also looked into using the Net Share command but in order to change share permissions with that, it has to delete and re-create the share drive completely.
You can use "Net Share". Use Invoke-Command to run it on each remote server.
Source - https://social.technet.microsoft.com/Forums/windowsserver/en-US/3edcabac-f1a8-4c4a-850c-8ba4697930a2/using-net-share-within-powershell
Example
Source - $server = "MYSRV" ; $user = "username" ; $SrvPath = "E:\Users\$user"
$sb = {
param($User,$SrvPath)
NET SHARE $User$=$SrvPath "/GRANT:Domain Admins,FULL" "/GRANT:$User,CHANGE" /REMARK:"Home folder for $SrvPath"
}
Invoke-Command -Computername "$Server" -ScriptBlock $sb -ArgumentList $user,$SrvPath
I'm trying to come up with a powershell script to add new users in AD that our HR department can use instead of sending me emails about that.
My script will ask for which department they wanna add the new user, username and the full name:
# ##########################################
# Determine if we have Administrator rights
Write-Host 'Checking user permissions... '
$windowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$windowsSecurityPrincipal = New-Object System.Security.Principal.WindowsPrincipal($windowsID)
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
If (!($windowsSecurityPrincipal.IsInRole($adminRole))) {
Write-Warning 'Current user does not have Administrator rights'
Write-Host 'Attempting to copy files to temporary location and restarting script'
# Get random file name
Do {
$temp = [System.IO.Path]::GetTempPath() + [System.IO.Path]::GetRandomFileName()
} Until (!(Test-Path -LiteralPath "$temp"))
# Create directory
Write-Host 'Creating temp directory... ' -NoNewLine
New-Item -Path "$temp" -ItemType 'Directory' | Out-Null
Write-Host 'done.'
# Copy script to directory
Write-Host 'Copying script to temp directory... ' -NoNewLine
Copy-Item -LiteralPath "$($myInvocation.MyCommand.Path)" "$temp" | Out-Null
Write-Host 'done.'
$newScript = "$($temp)\$($myInvocation.MyCommand.Name)"
# Start new script elevated
Write-Host 'Starting script as administrator... ' -NoNewLine
$adminProcess = New-Object System.Diagnostics.ProcessStartInfo
$adminProcess.Filename = ([System.Diagnostics.Process]::GetCurrentProcess()).Path
$adminProcess.Arguments = " -File `"$newScript`""
$adminProcess.Verb = 'runas'
Try {
[System.Diagnostics.Process]::Start($adminProcess) | Out-Null
}
Catch {
Write-Error 'Could not start process'
Exit 1
}
Write-Host 'done.'
Exit 0
}
#Change the execution policy
Set-ExecutionPolicy bypass
#Import the AD module
Import-Module ActiveDirectory
#Set variables
$title = "Add Users To The Domain"
$message = "For which department do you wanna add this user to?"
$rn = New-Object System.Management.Automation.Host.ChoiceDescription "&RN", `
"RN"
$callcenter = New-Object System.Management.Automation.Host.ChoiceDescription "&Call Center", `
"Call Center"
$management = New-Object System.Management.Automation.Host.ChoiceDescription "&Management", `
"Management"
$billing = New-Object System.Management.Automation.Host.ChoiceDescription "&Billing", `
"Billing"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($rn, $callcenter, $management, $billing)
$result = $host.ui.PromptForChoice($title, $message, $options, 0)
switch ($result)
{
0 {"You selected RN."}
1 {"You selected Call Center."}
2 {"You selected Management."}
3 {"You Selected Billing."}
}
$UName = Read-Host "What is the username you wanna give? Make sure it matches the username in the email."
$FName = Read-Host "What is the Full Name of the user?"
New-ADUser `
-Name $FName `
-Path "CN=Users,OU=$result,DC=Domain,DC=com" `
-SamAccountName $UName `
-DisplayName $FName `
-AccountPassword (ConvertTo-SecureString "password1" -AsPlainText -Force) `
-ChangePasswordAtLogon $true `
-Enabled $true
Add-ADGroupMember "Users" "$UName";
Each time I try I run it I get this error message:
New-ADUser : Directory object not found At
C:\Users\youssef\AppData\Local\Temp\ofit4gnq.1lp\AddUserHR.ps1:84
char:1
+ New-ADUser `
+ ~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (CN=TYoussef Tes...diatrics,DC=Com:String) [New-ADUser], ADIdentityNotFo
undException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,M
icrosoft.ActiveDirectory.Management.Commands.NewADUser
Add-ADGroupMember : Cannot find an object with identity: 'yousseft'
under: 'DC=TribecaPediatrics,DC=com'. At
C:\Users\youssef\AppData\Local\Temp\ofit4gnq.1lp\AddUserHR.ps1:92
char:1
+ Add-ADGroupMember "Users" "$UName";
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (yousseft:ADPrincipal) [Add-ADGroupMember], ADIdentityNotFoundException
+ FullyQualifiedErrorId : SetADGroupMember.ValidateMembersParameter,Microsoft.ActiveDirectory.Management.Commands.
AddADGroupMember
$result comes back as an integer so the path you're giving to New-ADUser looks like this:
"CN=Users,OU=0,DC=Domain,DC=com"
Which is why you're getting that error message, because more than likely there is no OU with the name "0" or any of the other options "1","2" or "3".
In your switch statement you should declare what each departments OU is called so you can put the new user into that OU.
you were very close, here's how i would modify your switch statement:
# ##########################################
# Determine if we have Administrator rights
Write-Host 'Checking user permissions... '
$windowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$windowsSecurityPrincipal = New-Object System.Security.Principal.WindowsPrincipal($windowsID)
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
If (!($windowsSecurityPrincipal.IsInRole($adminRole))) {
Write-Warning 'Current user does not have Administrator rights'
Write-Host 'Attempting to copy files to temporary location and restarting script'
# Get random file name
Do {
$temp = [System.IO.Path]::GetTempPath() + [System.IO.Path]::GetRandomFileName()
} Until (!(Test-Path -LiteralPath "$temp"))
# Create directory
Write-Host 'Creating temp directory... ' -NoNewLine
New-Item -Path "$temp" -ItemType 'Directory' | Out-Null
Write-Host 'done.'
# Copy script to directory
Write-Host 'Copying script to temp directory... ' -NoNewLine
Copy-Item -LiteralPath "$($myInvocation.MyCommand.Path)" "$temp" | Out-Null
Write-Host 'done.'
$newScript = "$($temp)\$($myInvocation.MyCommand.Name)"
# Start new script elevated
Write-Host 'Starting script as administrator... ' -NoNewLine
$adminProcess = New-Object System.Diagnostics.ProcessStartInfo
$adminProcess.Filename = ([System.Diagnostics.Process]::GetCurrentProcess()).Path
$adminProcess.Arguments = " -File `"$newScript`""
$adminProcess.Verb = 'runas'
Try {
[System.Diagnostics.Process]::Start($adminProcess) | Out-Null
}
Catch {
Write-Error 'Could not start process'
Exit 1
}
Write-Host 'done.'
Exit 0
}
#Change the execution policy
Set-ExecutionPolicy bypass
#Import the AD module
Import-Module ActiveDirectory
#Set variables
$title = "Add Users To The Domain"
$message = "For which department do you wanna add this user to?"
$rn = New-Object System.Management.Automation.Host.ChoiceDescription "&RN", `
"RN"
$callcenter = New-Object System.Management.Automation.Host.ChoiceDescription "&Call Center", `
"Call Center"
$management = New-Object System.Management.Automation.Host.ChoiceDescription "&Management", `
"Management"
$billing = New-Object System.Management.Automation.Host.ChoiceDescription "&Billing", `
"Billing"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($rn, $callcenter, $management, $billing)
$result = $host.ui.PromptForChoice($title, $message, $options, 0)
switch ($result)
{
0
{
"You selected RN."
$OU = "RN"
}
1
{
"You selected Call Center."
$OU = "CallCenter"
}
2
{
"You selected Management."
$OU = "Management"
}
3
{
"You Selected Billing."
$OU = "Billing"
}
}
$UName = Read-Host "What is the username you wanna give? Make sure it matches the username in the email."
$FName = Read-Host "What is the Full Name of the user?"
New-ADUser `
-Name $FName `
-Path "CN=Users,OU=$OU,DC=Domain,DC=com" `
-SamAccountName $UName `
-DisplayName $FName `
-AccountPassword (ConvertTo-SecureString "password1" -AsPlainText -Force) `
-ChangePasswordAtLogon $true `
-Enabled $true
Add-ADGroupMember "Users" "$UName";
I am trying to add remote server authentication to a PS1 batch file script.
So I can do this:
Copy-Item $src $destination -Credential $Creds
I created a password file that for now is in the same directory as the script. It simply contains the password string.
The line that causes the prompt:
Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File password.txt
When I remove the Read-Host command, the prompt goes away and the script executes as expected.
Question
What's the correct way to do remote server authentication?
Here is the new code in context of the script:
[...]
if(-not(Test-Path $destination)){mkdir $destination | out-null}
Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File password.txt
$PW = Get-Content password.txt | ConvertTo-Securestring
$Creds = New-Object -Typename System.Management.Automation.PSCredential -Argumentlist "SERVER02\Administrator",$PW
ForEach ($sourcefile In $(Get-ChildItem $source | Where-Object { $_.Name -match "Daily_Reviews\[\d{1,12}-\d{1,12}\].journal" }))
{
[...]
Copy-Item $src $destination -Credential $Creds
[...]
}
If you aren't worried about portability of the password file between machines, you can use this fairly secure approach:
# Capture once and store to file - DON'T PUT THIS PART IN YOUR SCRIPT
$passwd = Read-Host "Enter password" -AsSecureString
$encpwd = ConvertFrom-SecureString $passwd
$encpwd
$encpwd > $path\password.bin
# Later pull this in and restore to a secure string
$encpwd = Get-Content $path\password.bin
$passwd = ConvertTo-SecureString $encpwd
$cred = new-object System.Management.Automation.PSCredential 'john',$passwd
$cred
# NOTE: The "secret" required to rehyrdate correctly is stored in DPAPI - consequence:
# You can only rehydrate on the same machine that did the ConvertFrom-SecureString
If you need to debug this to see if $passwd is correct you can execute this while debugging:
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)
$str = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
$str