Server Management - Need script to monitor free space on server - windows

Need script to monitor free space on server and if the free memory space goes done certain threshold send alert mail.
PS- I think the solution will be Power Shell + Windows Timer Job. I am new to Power Shell though.

You can get free disk space using a command like this:
([wmi]"\\$computer\root\cimv2:Win32_logicalDisk.DeviceID='$drive'").FreeSpace
And you cand send an email using the function below:
function Send-EMail
{
param (
[parameter(Mandatory = $false)][string] $EmailTo = "<Your destination email>",
[parameter(Mandatory = $false)][string] $EmailFrom = "<The sending email address>",
[parameter(Mandatory = $false)][string] $EmailSubject = "Disk space problem",
[parameter(Mandatory = $false)][string] $SMTPServer = "<your smtp server>"
)
$MailMessage = New-Object System.Net.Mail.MailMessage
$MailMessage.From = ($EmailFrom)
$MailMessage.To.Add($EmailTo)
$MailMessage.Subject = $EmailSubject
$MailMessage.Body = $EmailBody
$MailMessage.IsBodyHTML = $true
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25)
$SMTPClient.Send($MailMessage)
}
Now combine these two functions in a PowerShell script that you can schedule with Windows scheduller.

You need to deal with WMI objects.
http://technet.microsoft.com/en-us/library/dd315295.aspx
Scripting might not be necessary. If you are on Wk3 Server you can enable quota management on volumes. W2k8 has extended quota management to volume folders also.
http://technet.microsoft.com/en-us/library/cc733029.aspx

Related

How do I get notification to my phone, when my PC starts?

I want to know how can I get notification to my phone when my PC goes online (Turns On).
TeamViewer can help you: https://www.teamviewer.com.
If you install this app on your pc and you sync your user on your iPhone, I guess that whenever your pc starts you will get a notification
If your pc have login in, you can create an powershell script for any time when some one login in your pc you receive an email. Or, this is hard, you can creat an powershell script for when an service start on your pc, send you an email too, you set the service on the start.
$filter="*[System[EventID=7036] and EventData[Data='SIOS DataKeeper']]"
$A = Get-WinEvent -LogName System -MaxEvents 1 -FilterXPath $filter
$Message = $A.Message
$EventID = $A.Id
$MachineName = $A.MachineName
$Source = $A.ProviderName
$EmailFrom = "sios#medfordband.com"
$EmailTo = "sios#medfordband.com"
$Subject ="Alert From $MachineName"
$Body = "EventID: $EventID`nSource: $Source`nMachineName: $MachineName `n$Message"
$SMTPServer = "smtp.gmail.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("sios#medfordband.com", "MySMTPP#55w0rd");
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
Like this, the event is the SIOS DataKeeper, when someone start the service you will receive an email. You can set the service for windows start, when the windows start you will receive an email.

How can I set the "Environment" > "Start the following program at logon" property on a local user using powershell?

Background:
I have a server with Windows 2008 R2 installed running as a terminal server session host. I have a long list of local users set-up and configured as remote desktop users. When the users remotely log on using remote desktop connection, a program automatically starts up. When the user closes that program, the session ends. This all works fine if I set it up manually.
My Question:
I have written a script to add a list of local users automatically and setup and configure the properties. The problem is that nowhere can I find how to set the "Environment" > "Start the following program at logon" properties. (See image for the properties I want to set)
A sample portion of my current script is as follow:
$computer = "localhost"
$userName = "aTestUser"
$objComputer = [ADSI]"WinNT://$computer"
$objUser = $objComputer.Create('user', $userName)
$objUser.SetPassword("Password")
$objUser.PSBase.InvokeSet('Description', "Some description for $userName")
$objUser.PSBase.InvokeSet('userflags', 512)
$objUser.PSBase.InvokeSet('passwordExpired', 1)
$objUser.SetInfo();
I also tried this command which doesn't work:
$objUser.PSBase.InvokeSet("TerminalServicesInitialProgram", "C:\programs\a_test_program.exe")
I have searched on Microsoft's MSDN site and Google and StackOverflow but could not find this specific property.
I found a solution here.
$ou = [adsi]"WinNT://127.0.0.1"
$user = $ou.psbase.get_children().find("test")
$user.PSBase.InvokeSet("TerminalServicesInitialProgram", "C:\logoff.bat")
$user.setinfo()
Okay, so I finally got it working. Seems like you have to first create the user then open it again for editing before the InvokeSet sets the TerminalServicesInitialProgram property.
I am not sure, maybe someone can share some experience or explanation.
Thank you to everyone for your help and assistance.
Working Code:
# Read the CSV file and create the users
# The CSV file structure is:
# UserName,FullName,Description
$Users = Import-Csv -Path "C:\Users.csv"
foreach ($User in $Users)
{
# adds user
$computer = "localhost"
$username = $User.UserName
#$username = "atest001"
$fullname = $User.FullName
#$fullname = "My Name"
$description = $User.Description
#$description = "A new user description"
$password = "MyGreatUnbreakableSecretPassword"
$objComputer = [ADSI]"WinNT://$computer"
$objUser = $objComputer.Create('user', $username)
$objUser.SetPassword($password)
$objUser.PSBase.InvokeSet("Description", $description)
$objUser.PSBase.InvokeSet('userflags', 65536)
$objUser.SetInfo();
# set password not to expire
#wmic USERACCOUNT WHERE "Name = '$username'" SET Passwordexpires=FALSE
# Add to groups
$group = [ADSI]"WinNT://./Power Users,group"
$group.Add("WinNT://$username,user")
$group = [ADSI]"WinNT://./WW_Users,group"
$group.Add("WinNT://$username,user")
$ou = [adsi]"WinNT://127.0.0.1"
$user = $ou.psbase.get_children().find($username)
$user.PSBase.InvokeSet("TerminalServicesInitialProgram", "C:\Program Files (x86)\Wonderware\InTouch\view.exe c:\program files (x86)\archestra\framework\bin\sibanyegold-kdce_app_tse1_test")
$user.PSBase.InvokeSet("MaxConnectionTime", 120)
$user.PSBase.InvokeSet("MaxDisconnectionTime", 1)
$user.PSBase.InvokeSet("MaxIdleTime", 30)
$user.PSBase.InvokeSet("BrokenConnectionAction", 1)
$user.PSBase.InvokeSet("ReconnectionAction", 1)
$user.PSBase.InvokeSet("FullName", $fullname)
$user.setinfo()
}

Windows duplicating printer with custom name

My organization uses a piece of software that has a printer name hard-coded into it PRN1.
Users are spread out through multiple locations; so it is impossible to just rename a single printer. Our networked printers are mapped by computer location via a login script; and some computers have locally attached printers.
The current proposed solution is to remote into each computer with the user logged in; re-map the users default printer; and manually rename it (Right click->Printer Prop...).
I'm trying to avoid this as we do not use roaming profiles and some users do move from location to location; and the users wouldn't understand why it suddenly isn't working.
Ideally I'd like to create a script that will automatically duplicate the users default printer; and name it PRN1.
$AllPrinters = gwmi win32_printer
$DefaultPrinter = $AllPrinters | where {$_.Default -eq $true}
rundll32 printui.dll,PrintUIEntry /ga /n $DefaultPrinter.SystemName + "\" + $DefaultPrinter.ShareName /z /b"PRN1"
Above is what I currently have; I know I'm not using the rundll32 command properly as the printer isn't being duplicated with the new name.
Any help or assistance would be greatly appreciated.
I use that rundll32 command here and there but never have solid luck with it.
You could do something like this by using wmi entirely. You may want to wrap a try catch around a large chunk of this to suppress errors and log output if users do end up having issues.
$Name = "PRN"
$AllPrinters = gwmi win32_printer
$DefaultPrinter = $AllPrinters | where {$_.Default -eq $true}
$objHelper = [WMICLASS]"\\localhost\root\cimv2:Win32_SecurityDescriptorHelper"
$print = [WMICLASS]"\\localhost\root\cimv2:Win32_Printer"
$print.Scope.Options.EnablePrivileges = $true
$newprinter = $print.createInstance()
$newprinter.drivername = $DefaultPrinter.DriverName
$newprinter.PortName = $DefaultPrinter.PortName
$newprinter.Shared = $false
$newprinter.Location = $DefaultPrinter.Location
$newprinter.Comment = $DefaultPrinter.Comment
$newprinter.DeviceID = $Name
$newprinter.PrintProcessor = $DefaultPrinter.PrintProcessor
$newprinter.PrintJobDataType = $DefaultPrinter.DataType
$newprinter.RawOnly = $DefaultPrinter.RawOnly
$result = $newprinter.Put()

How to compare age of local file with file on FTP server and download if remote copy is newer in PowerShell

I'm in the process of writing a PowerShell script to help in the process of setting up new PC's for my work. This will hopefully be used by more than just me so I'm trying to think of everything.
I have offline installers (java, flash, reader, etc) saved on our FTP server that the script downloads if a local copy hasn't already been saved in the Apps directory that gets created. Periodically the files on the FTP server will get updated as new versions of the programs are released. I want the script to have an option of checking for newer versions of the installers in case someone likes to carry around the local copies and forgets to check the server every now and then. It also will need to work in Windows 7 without any need to import additional modules unless there's an easy way to do that on multiple PC's at a time. I know about the import command, but the experiences I've had needed me to copy the module files into multiple places on the PC before it'd work.
Right now I haven't had much luck finding any solutions. I've found code that checks for modified dates on local files, or files on a local server, but nothing that deals with FTP other than uploading\downloading files.
Here's the last thing I tried. I tried a combination of what I found for local files with FTP. Didn't work too well.
I'm new to PowerShell, but I've been pretty good at piecing this whole thing together so far. However, this idea is becoming troublesome.
Thank you for the help.
$ftpsite = "ftp://ftpsite.com/folder/"
$firefox = (Get-Item $dir\Apps\install_firefox.exe).LastWriteTime.toString("MM/dd/yyyy")
if ($firefoxftp = (Get-ChildItem $ftpsite/install_firefox.exe | Where{$_.LastWriteTime -gt $firefox})) {
$File = "$dir\Apps\install_firefox.exe"
$ftp = "ftp://ftpsite.com/folder/install_firefox.exe"
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
$webclient.DownloadFile($uri, $File)
}
UPDATE:
Here's what I have after Martin's help. It kind of works. It downloads the file from FTP, but it's not comparing the remote and local correctly. The remote file returns 20150709140505 and the local file returns 07/09/2015 2:05:05 PM. How do I format one to look like the other before the comparison, and is "-gt" the correct comparison to use?
Thanks!
function update {
$ftprequest = [System.Net.FtpWebRequest]::Create("ftp://ftpsite.com/Script_Apps/install_firefox.exe")
$ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
$response = $ftprequest.GetResponse().StatusDescription
$tokens = $response.Split(" ")
$code = $tokens[0]
$localfile = (Get-Item "$dir\Apps\install_firefox.exe").LastWriteTimeUtc
if ($tokens -gt $localfile) {
write-host "Updating Firefox Installer..."
$File = "$dir\Apps\install_firefox.exe"
$ftp = "ftp://ftpsite.com/Script_Apps/install_firefox.exe"
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
$webclient.DownloadFile($uri, $File)
"Updated Firefox" >> $global:logfile
mainmenu
}
else {
Write-Host "Local Copy is Newer."
sleep 3
mainmenu
}
}
UPDATE 2:
Seems to be working! Here's the code. Thanks for the help!
function update {
$ftprequest = [System.Net.FtpWebRequest]::Create("ftp://ftpserver.com/Script_Apps/install_firefox.exe")
$ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
$response = $ftprequest.GetResponse().StatusDescription
$tokens = $response.Split(" ")
$code = $tokens[0]
$localtime = (Get-Item "$dir\Apps\install_firefox.exe").LastWriteTimeUtc
if ($code -eq 213) {
$tokens = $tokens[1]
$localtime = "{0:yyyymmddHHmmss}" -f [datetime]$localtime
}
if ($tokens -gt $localtime) {
write-host "Updating Firefox Installer..."
$File = "$dir\Apps\install_firefox.exe"
$ftp = "ftp://ftpserver.com/Script_Apps/install_firefox.exe"
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
$webclient.DownloadFile($uri, $File)
"Updated Firefox" >> $global:logfile
mainmenu
}
else {
Write-Host "Local Copy is Newer."
sleep 3
mainmenu
}
}
You cannot use the WebClient class to check remote file timestamp.
You can use the FtpWebRequest class with its GetDateTimestamp FTP "method" and parse the UTC timestamp string it returns. The format is specified by RFC 3659 to be YYYYMMDDHHMMSS[.sss].
That would work only if the FTP server supports MDTM command that the method uses under the cover (most servers do, but not all).
$url = "ftp://ftpsite.com/folder/install_firefox.exe"
$ftprequest = [System.Net.FtpWebRequest]::Create($url)
$ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
$response = $ftprequest.GetResponse().StatusDescription
$tokens = $response.Split(" ")
$code = $tokens[0]
if ($code -eq 213)
{
Write-Host "Timestamp is" $tokens[1]
}
else
{
Write-Host "Error" $response
}
It would output something like:
Timestamp is 20150709065036
Now you parse it, and compare against a UTC timestamp of a local file:
(Get-Item "install_firefox.exe").LastWriteTimeUtc
Or save yourself some time and use an FTP library/tool that can do this for you.
For example with WinSCP .NET assembly, you can synchronize whole remote folder with installers with a local copy with one call to the Session.SynchronizeDirectories. Or your can limit the synchronization to a single file only.
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::Ftp
$sessionOptions.HostName = "ftpsite.com"
$session = New-Object WinSCP.Session
# Connect
$session.Open($sessionOptions)
$transferOptions = New-Object WinSCP.TransferOptions
# Synchronize only this one file.
# If you remove the file mask, all files in the folder are synchronized:
$transferOptions.FileMask = "install_firefox.exe"
$session.SynchronizeDirectories(
[WinSCP.SynchronizationMode]::Local, "$dir\Apps", "/folder",
$False, $False, [WinSCP.SynchronizationCriteria]::Time,
$transferOptions).Check()
To use the assembly, just extract a contents of .NET assembly package to your script folder. No other installation is needed.
The assembly supports not only the MDTM, but also other alternative methods to retrieve the timestamp.
See also a related Powershell example that shows both the above code and other techniques.
(I'm the author of WinSCP)

How can I monitor the Exchange 2003 Event Service from my application?

We had our server guys set up something on Exchange so that for a particular email address, any attachments sent to it will be dumped to a location on the file server.
The Exchange Event Service controls this behaviour, but it seems that this particular service fails fairly often. I dont know why - I dont have access to the Exchange server and it is run by a team in a different country.
Is it possible to monitor this exchange service programatically so I can warn the users if it goes down? I know that the 'right' solution is to have this handled by the Exchange team, but because of the timezone differences (and their massive workload) I really need to handle it from my end.
Could you do something like this with WebDav?
You could use the following powerShell script:
# Getting status of Exchange Services and look for anything that's "stopped"
$ServiceStatus = get-service MSExch* | where-object {$_.Status -eq "stopped"}
# Convert Result to String
$ServiceStatusText = $ServiceStatus | fl | Out-String
# If $ServiceStatus <> $null then send notification
If ($ServiceStatus -ne $null)
{
###Exchange Server Values
$FromAddress = "Exchange-Alert#YOUR_DOMAIN.local"
$ToAddress = "your_address#YOUR_DOMAIN.com"
$MessageSubject = "CRITICAL: An exchange service is has stopped"
$MessageBody = "One or more Exchange services has stopped running or crashed. Please check the server ASAP for possible issues`n"
$MessageBody = $MessageBody + $ServiceStatusText
$SendingServer = "msexch02.pnlab.local"
###Create the mail message and add the statistics text file as an attachment
$SMTPMessage = New-Object System.Net.Mail.MailMessage $FromAddress, $ToAddress, $MessageSubject, $MessageBody
###Send the message
$SMTPClient = New-Object System.Net.Mail.SMTPClient $SendingServer
$SMTPClient.Send($SMTPMessage)
}
# Else don't do anything and exit
Else
{
$null
}

Resources