Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

Wednesday, February 26, 2020

Set RegisterAllProvidersIP value for WFC and Quorum Take Online/Offline

I am using powershell to get and set RegisterAllProvidersIP cluster parameter.

#Get Network Name
Get-ClusterResource  -Cluster "SQLDRPOCACN"

# Get Cluster parameter
Get-ClusterResource "SQLDRPOCAG_SQLDRPOCALS"  -Cluster "SQLDRPOCACN" | Get-ClusterParameter

# Set ClusterParameter RegisterAllProvidersIP
Get-ClusterResource “SQLDRPOCAG_SQLDRPOCALS” | Set-ClusterParameter RegisterAllProvidersIP 0


The powershell script will take Quorum take online and offline.

Get-ClusterResource  -Cluster "SQLDRPOCACN"

#Bring up File Share Witness online
Get-ClusterResource "File Share Witness"  -Cluster "SQLDRPOCACN" | Start-ClusterResource -Name "File Share Witness"
#Take File Share Witness offline
Get-ClusterResource "File Share Witness"  -Cluster "SQLDRPOCACN" | Stop-ClusterResource -Name "File Share Witness"


Thank you for reading my blog.

Friday, March 24, 2017

Renaming NIC , NetBios Setting, Disabling Protocols

The objective of powershell script is to automate renaming NIC, changing NetBios setting in Private and Public NIC and Disabling some protocols in Private NIC.


I created the following powershell scripts to automate the changes. The changes are necessary to set up AlwaysOn availability group severs in my process. Thank you for reading.








import-module Netadapter

Get-NetAdapter | ? status -eq 'up'| Get-NetIPAddress -ea 0 -AddressFamily IPv4 | Select InterfaceAlias, IPAddress

#Rename NIC Public 10.*
$PubNic=Get-NetAdapter | ? status -eq 'up'| Get-NetIPAddress -ea 0 -AddressFamily IPv4 | where IPAddress -like '10.*'|Select InterfaceAlias
$PubNicName= $PubNic.InterfaceAlias
$NewPublicNicName = "Public NIC"
Rename-NetAdapter -Name $PubNicName -NewName $NewPublicNicName

#Rename NIC Private 192.*
$PriNic=Get-NetAdapter | ? status -eq 'up'| Get-NetIPAddress -ea 0 -AddressFamily IPv4 | where IPAddress -like '192.*'|Select InterfaceAlias
$PriNicName= $PriNic.InterfaceAlias
$NewPrivateNicName ="Private NIC"
Rename-NetAdapter -Name $PriNicName -NewName $NewPrivateNicName


#In Public NIC, Enable NetBios over TCP
#0: Enable Netbios via DHCP.1: Enable Netbios on the interface.2: Disable Netbios on the interface.

$PubNicConfig = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'"  | where {$_.IpAddress -like '10.*'}
$PubNicConfig.SetTcpipNetbios(1)
#Verify the changes
Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'"  | where {$_.IpAddress -like '10.*'}|Select IpAddress,Description,TcpipNEtbiosOptions |format-list


#In Private NIC, Enable NetBios over TCP
#0: Enable Netbios via DHCP.1: Enable Netbios on the interface.2: Disable Netbios on the interface.

$PriNicConfig = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'"  | where {$_.IpAddress -like '192.*'}
$PriNicConfig.SetTcpipNetbios(2)
#Verify the changes
Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'"  | where {$_.IpAddress -like '192.*'}|Select IpAddress,Description,TcpipNEtbiosOptions |format-list


#Private NIC, Do Not Register this connection  address in DNS
$PriNicConfig = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'"  | where {$_.IpAddress -like '192.*'}
$PriNicConfig.SetDynamicDNSRegistration($false,$false)  
# Verify Wins, Netbios setting
Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'"  | where {$_.IpAddress -like '192.*'} |Select * |format-list


#Disable Protocols Public and Private protocols

#Disable Client for Microsoft Network
Disable-NetAdapterBinding -Name 'Private NIC' -ComponentID ms_msclient
#Disable File and Printer Sharing for Microsoft Networks
Disable-NetAdapterBinding -Name 'Private NIC' -ComponentID ms_server
#Enable Ipv6 for both Private and Public NIC
Enable-NetAdapterBinding -Name 'Private NIC' -ComponentID ms_tcpip6
Enable-NetAdapterBinding -Name 'Public NIC' -ComponentID ms_tcpip6
#Verify the changes
Get-netadapterbinding -Name 'Private NIC'
Get-netadapterbinding -Name 'Public NIC'

Changing NIC Bindings Order using Powershell Script

NIC Bindings Order


I did a lot of research on how to change NIC Binding Order using powershell. I am changing the binding Order to meet the requirement of Always On server setup. I created the following powershell script which changes registry of NIC binding. After you run the script you will not see the binding order is changed in UI but it is actually updated when you run IP config. I believe that the setting not being updated in UI is a bug in Windows.

In Adapters and Bindings tab, I move Public NIC on top of Private NIC. The powershell script will update 3 places in - Bind , Export and Route under CurrentControl set in Registry.



#-------------------------Public Setting ID------------------------------------------------#

$PublicSettingID = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPenabled = $true" | where {$_.IpAddress -like '10.*'}|select Settingid
$PubSettingID = $PublicSettingID.Settingid
Write-host $PubSettingID

#-------------------------Private Setting ID------------------------------------------------#

$PrivateSettingID = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPenabled = $true" | where {$_.IpAddress -like '192.*'}|select Settingid
$PriSettingID = $PrivateSettingID.Settingid
Write-host $PriSettingID

#---------------------------------BIND------------------------------------------------------#
$BindNewOrder = @()
$writereg = $null
$Bindkey = 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage'
$Bindvalue = 'Bind'

#get values in registry
$BindOldOrder = (Get-ItemProperty $Bindkey $Bindvalue).$Bindvalue 
write-host $BindOldOrder

$BindPubSettingID='\Device\'+$PubSettingID
$BindPriSettingID='\Device\'+$PriSettingID

#Order
if ($BindOldOrder -contains $BindPubSettingID) {$BindNewOrder += $BindPubSettingID}
if ($BindOldOrder -contains $BindPriSettingID) {$BindNewOrder += $BindPriSettingID}
if ($BindOldOrder.count -gt $BindNewOrder.count) {$BindNewOrder += $BindOldOrder}


$BindNewOrder = $BindNewOrder | select -unique
Write-host $BindNewOrder

#Change registry valules
Set-ItemProperty -path $Bindkey -Name $Bindvalue -Value $BindNewOrder

#>

#----------------------------EXPORT----------------------------------------------------#

$ExportNewOrder = @()
$Exportkey = 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage'
$Exportvalue = 'Export'
$ExportPubSettingID = '\Device\Tcpip_' + $PubSettingID
$ExportPriSettingID = '\Device\Tcpip_' + $PriSettingID

Write-host $ExportPubSettingID
Write-host $ExportPriSettingID

#get values in registry
$ExportOldOrder = (Get-ItemProperty $Exportkey $Exportvalue).$Exportvalue 
write-host $ExportOldOrder

#Order
if ($ExportOldOrder -contains $ExportPubSettingID) {$ExportNewOrder += $ExportPubSettingID}
if ($ExportOldOrder -contains $ExportPriSettingID) {$ExportNewOrder += $ExportPriSettingID}
if ($ExportOldOrder.count -gt $ExportNewOrder.count) {$ExportNewOrder += $ExportOldOrder}


$ExportNewOrder = $ExportNewOrder | select -unique
Write-host $ExportNewOrder
Set-ItemProperty -path $Exportkey -Name $Exportvalue -Value $ExportNewOrder


#-----------------------------ROUTE-------------------------------------------------------#

$RouteNewOrder = @()
$Routekey = 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage'
$Routevalue = 'Route'
$RoutePubSettingID = '"' + $PubSettingID + '"'
$RoutePriSettingID = '"' + $PriSettingID + '"'

Write-host $RoutePubSettingID
Write-host $RoutePriSettingID

#get values in registry
$RouteOldOrder = (Get-ItemProperty $Routekey $Routevalue).$Routevalue 
write-host $RouteOldOrder

#Order
if ($RouteOldOrder -contains $RoutePubSettingID) {$RouteNewOrder += $RoutePubSettingID}
if ($RouteOldOrder -contains $RoutePriSettingID) {$RouteNewOrder += $RoutePriSettingID}
if ($RouteOldOrder.count -gt $RouteNewOrder.count) {$RouteNewOrder += $RouteOldOrder}


$RouteNewOrder = $RouteNewOrder | select -unique
Write-host $RouteNewOrder
Set-ItemProperty -path $Routekey -Name $Routevalue -Value $RouteNewOrder


After you run the script, you will see the output similar to below.



The changes takes affect on NIC Binding but UI is not updated. It think it is a bug in Microsoft windows. The UI does not change even after rebooting the server.When you run Ipconfig /all on the server, it returns public ip address then private ip address.







Changing NIC Provider Order with Powershell Script

NIC Provider Order


Hello 2017! I hope everyone had a great 2016. My son was born in December 2016 and 2016 was the best year for me.

Now, I am back to my full time job. This is my first blog of 2017.

Here we go.....

Before configuring Availability Groups, we will need to configure NIC Provider Order and Binding Order. Usually, I changed them manually. If we are changing it in multiple servers, it will take time to configure them. So, I created a powershell script to change NIC provider order.

Manual Steps - Screenshots below are the steps how to change NIC provider order manually.


In Network and Sharing,
Click on Public NIC, press Alt + N , Click on Advanced Settings




Move Microsoft Windows Network on the top



The powershell script below is how to change Provider Order. I want to move Microsoft Windows Network on top of the rest.I am planning to use it in VM template deployment. Thank you for visiting my page.

$newproder = @()
$writereg = $null
$key = 'HKLM:\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order'
$value = 'ProviderOrder'

#get values in registry
$proder = (Get-ItemProperty $key $value).$value | % {$_.split(",")}

#Order
if ($proder -contains "LanmanWorkstation") {$newproder += "LanmanWorkstation"}
if ($proder -contains "RDPNP") {$newproder += "RDPNP"}
if ($proder.count -gt $newproder.count) {$newproder += $proder}

$newproder = $newproder | select -unique

#Make a string
$newproder|ForEach-Object{$writereg += $_+","}

$writereg = $writereg.substring(0,$writereg.length-1)

#Change registry valules
Set-ItemProperty -path $key -Name $value -Value $writereg

I will reboot the server to take affect the changes. 

My reference is 

https://social.technet.microsoft.com/Forums/scriptcenter/en-US/9a91540a-8c24-4f97-a433-70e4c9c7b709/change-network-providerorder-using-powershell?forum=ITCG

Thursday, July 28, 2016

Checking Server online Status - PowerShell

We managed 100 + servers and we want make sure they come back after monthly maintenance reboot. We will run the following script by confirming the servers are Up. I retrieve servername from a Table called SQLServers from Database - DBA_ServerDW from ServerInstance name SQLTEST.

$servername = invoke-sqlcmd -ServerInstance SQLTEST -Database DBA_ServerDW `
-Query "select ServerName from DBA_ServerDW.dbo.SQLServers
where servername not like '%\%'"
ForEach ($server in $servername)
{
   # Ping the machine to see if it's on the network
   $ServerN=$server.ServerName
   $results = Get-WMIObject -query "select StatusCode from Win32_PingStatus where Address = '$ServerN'"
   $responds = $false  
   ForEach($result in $results) {
      # If the machine responds break out of the result loop and indicate success
      if ($result.statuscode -eq 0) {
         $responds = $true
         break
      }
   }
         If ($responds) {
      # Gather info from the server because it responds
      Write-Output "$ServerN responds"
   } else {
      # Let the user know we couldn't connect to the server
      Write-Output "$ServerN does not respond"
   }
}

Friday, June 24, 2016

PowerShell - Find AlwaysOn Primary node Report

I was working on a powershell script which tells me which node is AlwaysOn primary replica. We have 38 servers which participate in AlwaysOn availability group technology. This script will help you to determine which server is a primary replica without logging into each server and find out.

NOTE:

I set up a path which is for error log at E:\PowerShell\GetAlwaysOnPrimary\
DBATestServer is our DBA server and DBA_ServerDW is DBA inventory database
SQLServers table is in DBA_ServerDW database. The table is already populated with a list of servers that we manage in our organization.

First, I will get a list of server names from SQLServers table. Then each server will be passed in for loop. I use invoke-sqlcmd command to all sql statements. Inside for each loop , I will get each server info if it is primary replica. Finally, I will omit all null results from the query and insert only returned data to a table AlwaysOnPrimary in DBA_ServerDW database. Thank you for reading my blog. Enjoy scripting!


$($errorlog = 'E:\PowerShell\GetAlwaysOnPrimary\Error.txt'
Clear-Content $errorlog

#Get Server List from SQL server inventory table, exclude name instances

$servername = invoke-sqlcmd -ServerInstance DBATestServer -Database DBA_ServerDW `
-Query "select servername from SQLServers
where SQLservers.Purpose like '%AlwaysOn%'"

foreach($server in $servername){
Try{

#convert system.object data type to String

$ServerN=$server.ServerName

$AG = invoke-sqlcmd -ServerInstance $ServerN -Database master `
                -Query "IF SERVERPROPERTY ('IsHadrEnabled') = 1
BEGIN
SELECT
  RCS.replica_server_name as ServerName
 ,AGC.name as AvailablityGroupName
  , ARS.role_desc as Role
 , AGL.dns_name as ListenerName
FROM
 sys.availability_groups_cluster AS AGC
  INNER JOIN sys.dm_hadr_availability_replica_cluster_states AS RCS
   ON
    RCS.group_id = AGC.group_id
  INNER JOIN sys.dm_hadr_availability_replica_states AS ARS
   ON
    ARS.replica_id = RCS.replica_id
  INNER JOIN sys.availability_group_listeners AS AGL
   ON
    AGL.group_id = ARS.group_id
WHERE
 ARS.role_desc = 'PRIMARY'
END"

$SName = $AG.ServerName
$GName = $AG.AvailablityGroupName
$Role  = $AG.Role
$LN    = $AG.ListenerName

if ($SName)
        {
                invoke-sqlcmd -ServerInstance DBATestServer -Database DBA_ServerDW `
                -Query  "INSERT INTO AlwaysOnPrimary(ServerName,AvailabilityGroupName,Role,ListenerName)
                        VALUES ('$SName','$GName','$Role','$LN')"
          }
}
Catch
{    Clear-Content $errorlog
     "Fail to get information $ServerN +' ' + $RunTime :$_" |Out-File $errorlog -Append
}
}

Thursday, January 15, 2015

PowerShell - Automatic Reboot AlwaysOn Server if AlwaysOn Availability group is ready to failover

Recently, we have encountered Secondary replica was in Resolving State and took 3 minutes to take over primary role when we forced reboot primary server from Task scheduler.

I have read the following troubleshooting page from MS http://support.microsoft.com/kb/2833707. There were 3 cases that can cause secondary replica in RESOLVING state. In Case 3, 

"... In order to automatically fail over, all availability databases that are defined in the availability group must be in a SYNCHRONIZED state between the primary replica and the secondary replica. When an automatic failover occurs, this synchronization condition must be met in order to make sure that there is no data loss. Therefore, if one availability database in the availability group in the synchronizing or not synchronized state, automatic failover will not successfully transition the secondary replica into the primary role...."

As we decided we will continue to schedule to reboot the servers on monthly basis scheduled reboot, we will need to make sure AG group is in Synchronized or fail over ready state.

To do so, I created a powershell script based on the following query. The query will check if AG group is ready to fail over.

Select database_name, is_failover_ready from sys.dm_hadr_database_replica_cluster_states where replica_id in (select replica_id from sys.dm_hadr_availability_replica_states)

In my script, I verified Secondary SQL server status in case they are paused/stopped. 
Enjoy script....

## The following PS script check the other replica is ready for failover. If it is ready, the current replica will be rebooted.
## The script can be used for rebooting primary replica or secondary replica automaically. It can be scheduled in Task Scheduler.

##Other Replica Node

$OtherReplica ='Server2'

#Local Host/Server which is going to reboot
$CurrentReplica='Server1'
#$env:COMPUTERNAME

#First, Check Other Replica is online by Pinging the server wait for 4 replies.
if(Test-Connection -ComputerName $OtherReplica -count 4 -ea 0 -Quiet)
 {
       
       # If the other server replies ping, check the status of SQL server
             
       Write 'The Other Server is alive'

       # Get SQL server status of the other server
       $SQLserverState = Get-WmiObject win32_service -ComputerName $OtherReplica -Filter "Name = 'MSSQLSERVER'"|Select State
                   
         If($SQLserverState.State -eq 'Stopped')
         {
                   Write 'Do Not Reboot' -ea Stop
         }
         
         If($SQLserverState.State -eq 'Paused')
          {
                     Write 'Do Not Reboot' -ea Stop
          }

        #If SQL server status of the other server is running, get the failover status from database
        If($SQLserverState.State -eq 'Running')
         {
                           
                    
                   $DBconn = new-object System.Data.SqlClient.SqlConnection("server=$OtherReplica;Trusted_Connection=true");
                   $DBQry  = 'Select min(cast(is_failover_ready as int)) from sys.dm_hadr_database_replica_cluster_states where replica_id in (select replica_id from sys.dm_hadr_availability_replica_states)'
                   $DBconn.Open()
                   $DBcmd = new-object System.Data.SqlClient.SqlCommand ($DBQry, $DBconn);
                   $Reader = $DBcmd.ExecuteReader()
                   while($Reader.Read()){
                   $FailOverStatus = $Reader.GetValue($1)           
                   }
                   
                   # If $FailOverStatus is 1, it is ready to failover. If $FailOverSatus is 0, it is not ready to failover
                
                   If($FailOverStatus -eq 1)
                   {

                    Write 'Server is Ready to Reboot...Rebooting...'
                    Restart-Computer -ComputerName $CurrentReplica -Force
                   }
                     If($FailOverStatus -eq 0)
                   {

                    Write 'Do Not Reboot' -ea Stop
                   }

                   $DBconn.Close()
           }

}
  else
  {
       Write 'Server is offline'
  }


Tuesday, October 28, 2014

How to run Powershell in Windows Task Scheduler

Action : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add Arguments : -noprofile -executionpolicy RemoteSigned -file E:\CopyBakPS\Powershell.ps1


Monday, August 18, 2014

PowerShell - Get Maintenance Plan of SQL servers

Some of us know SQL server maintenance plan is encrypted in xml file. I believe you can find a lot resources how to query SQL server maintenance plan. The hardest part of the query is I need to know how to unwrap xml and retrieve information.
I found very useful sites http://sqlchad.com/?p=339 and http://www.sqlballs.com/2013/01/how-do-you-query-maintenance-plan.html. They gave me what I am really looking for. I enhanced the script from the site and combine with powershell script to retrieve full and tlog backup maintenance plan from all SQL servers which includes maintenance clean up task. The script works in 2005/2008R2 and 2012.

Enjoy Scripting...

$($ServerList = 'E:\PowerShell\SQLServerList\SQLSvrList.txt'
$exportcsv ='E:\PowerShell\GetMaintenancePlan\BackupInfo.csv'
Clear-Content $exportcsv
$servername = Get-Content $ServerList
$errorlog = 'E:\PowerShell\GetMaintenancePlan\Error.txt'
$RunTime = $(get-date -f MM-dd-yyyy_HH_mm_ss)
if(!(test-path $ServerList))
{
    Write-Error "SQLSvr.txt is not Found" -ea Stop
}
if(test-path $ServerList)
{
foreach($server in $servername){
Try{
$sqlconn = new-object System.Data.SqlClient.SqlConnection("server=$server;Trusted_Connection=true");
$query = "

IF SUBSTRING(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0,CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0)) = 9
BEGIN

          WITH XMLNAMESPACES ('www.microsoft.com/SqlServer/Dts' AS DTS
          , 'www.microsoft.com/sqlserver/dts/tasks/sqltask' AS SQLTask)
          ,ssis AS (
              SELECT name
                  , CAST(CAST(packagedata AS varbinary(MAX)) AS XML) AS package
              FROM [msdb].[dbo].[sysdtspackages90]
              WHERE packagetype = 6

             )
          SELECT '$server' as ServerName,s.name as MaintenancePlanName,
               CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupAction)[1]', 'INT')
                    WHEN 0 THEN
                         CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupIsIncremental)[1]', 'bit')
                              WHEN 1 THEN 'DIFFERENTIAL'
                              WHEN 0 THEN 'FULL'
                              ELSE 'Maintenance clean Up'
                         END
                    WHEN 1 THEN 'FILES'
                    WHEN 2 THEN 'LOG'
                    ELSE 'UNKNOWN'
               END as BackupType,
               CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupCompressionAction)[1]', 'int')
                    WHEN 0 THEN 'SERVER DEFAULT CONFIG'
                    WHEN 1 THEN 'YES'
                    WHEN 2 THEN 'NO'
               END as Compressed,
               c.value('(SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath)[1]', 'VARCHAR(MAX)') as BackupLocation
          FROM ssis s
              CROSS APPLY package.nodes('//DTS:ObjectData') t(c)
          WHERE c.exist('SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath') = 1
       

END


ELSE IF SUBSTRING(CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0,CHARINDEX('.',CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR),0)) >= 10

BEGIN

          WITH XMLNAMESPACES ('www.microsoft.com/SqlServer/Dts' AS DTS
          , 'www.microsoft.com/sqlserver/dts/tasks/sqltask' AS SQLTask)
          ,ssis AS (
              SELECT name
                  , CAST(CAST(packagedata AS varbinary(MAX)) AS XML) AS package
              FROM [msdb].[dbo].[sysssispackages]
              WHERE packagetype = 6

             )
          SELECT '$server' as ServerName,s.name as MaintenancePlanName,
             CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupAction)[1]', 'INT')
                     WHEN 0 THEN
                         CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupIsIncremental)[1]', 'bit')
                              WHEN 1 THEN 'DIFFERENTIAL'
                              WHEN 0 THEN 'FULL'
                              ELSE 'Maintenance clean Up'
                         END
                    WHEN 1 THEN 'FILES'
                    WHEN 2 THEN 'LOG'
                    ELSE 'Maintenance clean Up'
               END as BackupType,
  COALESCE(c.value('(SQLTask:SqlTaskData/@SQLTask:BackupFileExtension)[1]','varchar(1000)'),
  c.value('(SQLTask:SqlTaskData/@SQLTask:FileExtension)[1]','varchar(1000)')) as Extension,
           COALESCE(c.value('(SQLTask:SqlTaskData/@SQLTask:BackupFileExtension)[1]','varchar(1000)'),
  c.value('(SQLTask:SqlTaskData/@SQLTask:FileExtension)[1]','varchar(1000)'))+'$server' as PK,

'DELETE backups older than ' + c.value('(SQLTask:SqlTaskData/@SQLTask:RemoveOlderThan)[1]','VARCHAR(3)') +
CASE c.value('(SQLTask:SqlTaskData/@SQLTask:TimeUnitsType)[1]','VARCHAR(10)') --0=Daily,1=Weekly,2=Monthly,3=Yearly,5=Hourly
WHEN 0 THEN ' Day(s)'
WHEN 1 THEN ' Week(s)'
WHEN 2 THEN ' Month(s)'
WHEN 3 THEN ' Year(s)'
WHEN 4 THEN ' Minute(s)'
WHEN 5 THEN ' Hour(s)'
END AS Del_Freqency,
       CASE c.value('(SQLTask:SqlTaskData/@SQLTask:BackupCompressionAction)[1]', 'int')
                    WHEN 0 THEN 'SERVER DEFAULT CONFIG'
                    WHEN 1 THEN 'YES'
                    WHEN 2 THEN 'NO'
               END as Compressed,
  c.value('(SQLTask:SqlTaskData/@SQLTask:BackupVerifyIntegrity)[1]', 'BIT') as BackupVerified,
               c.value('(SQLTask:SqlTaskData/@SQLTask:BackupDestinationAutoFolderPath)[1]', 'VARCHAR(MAX)') as BackupLocation



          FROM ssis s
              CROSS APPLY package.nodes('//DTS:ObjectData') t(c)
 where s.name in('Full BackUp','Transaction Logs')
END

"
$sqlconn.Open()
$sqlcmd = new-object System.Data.SqlClient.SqlCommand ($query, $sqlconn);
$sqlcmd.CommandTimeout = 0;
#$dr = $sqlcmd.ExecuteReader();
$dr = New-Object System.Data.SqlClient.SqlDataAdapter
$dr.SelectCommand = $sqlcmd
$dt = New-Object System.Data.DataTable
$dr.fill($dt) | out-null
$dt
}
Catch
{    Clear-Content $errorlog
    "Fail to get information $server +' ' + $RunTime :$_" |Out-File $errorlog -Append
}
}
})|Export-csv $exportcsv -noType
Get-Job | Wait-Job | Out-Null
Remove-Job -State Completed


Thank you.

Friday, August 8, 2014

Powershell - Get Servers Information

The original script came from MSSQLTIPS.COM

http://www.mssqltips.com/sqlservertip/3045/script-to-get-cpu-and-cores-for-sql-server-2012-licensing/#comments

I enhanced the script from MSSQLTIPS and added additonal information such as SQL server maxmemory, Ip address and etc...There are two script files. SQLServerInfo.ps1 contains a function Get-ServerInfo which retrieves information from all the servers. SQLServerInfo_Call.ps1 is to call SQLServerInfo.ps1 script.
You saved two script files in E:\ or C:\ as powershell files. You just need to change the path of the $errorlog,$exportcvs variables if you are putting your files in different drives.

How to run the script. - Open SQLServerInfo_Call and Click Run.


Enjoy scripting..

SQLServerInfo.ps1

param([string]$SQLServerList=$(Throw
"Paramater missing: -SQLServerList ConfigGroup"))

$errorlog = 'E:\PowerShell\SQLServersInfo\Error.txt'
$RunTime = $(get-date -f MM-dd-yyyy_HH_mm_ss)

Function Get-ServerInfo{
    [CmdletBinding()]
    Param(
    [parameter(Mandatory = $TRUE,ValueFromPipeline = $TRUE)]   [String] $ComputerName
    # I have defined an input parameter - computer name, This can accept input from the pipleline.
    #This means you can call this function in two distinct ways
    #Get-Content names.txt | Get-ServerInfo
    #OR
    #Get-ServerInfo –computername SERVER1,SERVER2
    )

 
 
    Process{
 
                Try{

         
            $sqlconn = new-object System.Data.SqlClient.SqlConnection(`
            "server=$ComputerName;Trusted_Connection=true");
                     
            #SQL server Edition
            $query = "select SERVERPROPERTY('ProductVersion') As ProductVersion,SERVERPROPERTY('Edition') as Edition;"
         
            #SQL server Memory
            $query2 = "select value as MaxMemory from sys.configurations where name like 'max server memory (MB)';"
     
         
            #execute query Get Product Version and Edition
            $sqlconn.Open()
            $sqlcmd = new-object System.Data.SqlClient.SqlCommand ($query, $sqlconn);
            $sqlcmd.CommandTimeout = 0;
            $dr = $sqlcmd.ExecuteReader();        
                   
            while ($dr.Read()) {
             $SQLVersion=$dr.GetValue(0);
             $SQLEdition=$dr.GetValue(1);
            }
         
            $dr.Close()
            $sqlconn.Close()
           
            #execute query Get SQL Server Max Memory
            $sqlconn.Open()
            $sqlcmd2 = new-object System.Data.SqlClient.SqlCommand ($query2, $sqlconn);
            $sqlcmd2.CommandTimeout = 0;
            $dr2 = $sqlcmd2.ExecuteReader();
           
             while ($dr2.Read()) {
             $SQLMaxMemory=$dr2.GetValue(0);
           
            }
                 
            $dr2.Close()
            $sqlconn.Close()
                 
         
         
 
            #Get processors information          
            $CPU=Get-WmiObject -ComputerName $ComputerName -class Win32_Processor
         
            #Get Computer model information
            $OS_Info=Get-WmiObject -ComputerName $ComputerName -class Win32_ComputerSystem
         
            #Get Computer IP Address        
            $OS_IP =Get-WmiObject -ComputerName $ComputerName -class Win32_NetworkAdapterConfiguration -Filter IPEnabled=True                    
         
         
            #Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $ComputerName -Property IPAddress
            #Get OS Version
            $OS_Ver=Get-WmiObject -ComputerName $ComputerName -class Win32_OperatingSystem
   
           #Reset number of cores and use count for the CPUs counting
           $CPUs = 0
           $Cores = 0
         
           foreach($Processor in $CPU){

           $CPUs = $CPUs+1
         
           #count the total number of cores      
           $Cores = $Cores+$Processor.NumberOfCores
     
          }
       
          #Calculate Physical Memory
          $totalMemory = 0
       
           #Get Computer Physical Memory Information
           $OS_Mem=Get-WmiObject -ComputerName $ComputerName -class Win32_PhysicalMemory
       
          foreach($ram in $OS_Mem)
          {
           $totalMemory+= $ram.capacity
          }
       
         
           $InfoRecord = New-Object -TypeName PSObject -Property @{
                    Server = $ComputerName;
                    OS = $OS_Ver.Caption;                      
                    Model = $OS_Info.Model;
                    IpAddress = $OS_IP.IPAddress;
                    Domain = $OS_Info.Domain;
                    SQLEdition = $SQLEdition;
                    SQLVersion = $SQLVersion;
                    PhysicalMemory_MB = $totalMemory/(1024 * 1024);
                    SQLMaxMemory_MB = $SQLMaxMemory;
                    CPUNumber = $CPUs;
                    TotalCores = $Cores;
                    };

                    }

    Catch{

     "Fail to get information $ComputerName +' ' + $RunTime :$_" |Out-File $errorlog -Append
    }
 
    Write-Output $InfoRecord
     }
                         
   }
#loop through the server list and get information about CPUs, Cores and Default instance edition
   $exportcsv ='E:\PowerShell\SQLServersInfo\SQLServerInfo.csv'
   Get-Content $SQLServerList | Foreach-Object {Get-ServerInfo $_ }|Select Server, OS, Model,{$_.IpAddress},Domain,SQLEdition,SQLVersion,PhysicalMemory_MB,SQLMaxMemory_MB,CPUNumber,TotalCores|Export-csv $exportcsv  -noType -Append
   Get-Job | Wait-Job | Out-Null
   Remove-Job -State Completed

-------------End--------------
SQLSeverInfo_Call.ps1

SL "E:\PowerShell\SQLServersInfo"
.\SQLServerInfo.ps1 -SQLServerList "E:\PowerShell\SQLServerList\SQLSrvList.txt"



Powershell - Get ALL SQL services running Status in SQL server VMs

I created the following script to check any SQL services running on SQL server VMs. The script will read servers name in SQLSvrList.txt file and retrieve SQL services running status and startmode from WMI service module. It will export to SQLServerStatus.csv. If there is error in connection, the errors will be written to Error.txt.

Enjoy Scripting....

$($ServerList = 'E:\PowerShell\SQLServerList\SQLSvrList.txt'
if(!(test-path $ServerList))
{
    Write-Error "SQLSvrList.txt is not Found" -ea Stop
}
if(test-path $ServerList)
{
$errorlog = 'E:\PowerShell\SQLServerStatus\Error.txt'
$exportcsv ='E:\PowerShell\SQLServerStatus\SQLSeverStatus.csv'
$servername = Get-Content $ServerList
Clear-Content $exportcsv
foreach($server in $servername){
Try{

$WMI=Get-WmiObject win32_service -computer $server | Where-Object {$_.DisplayName -match 'SQL'}|

Select-Object @{Expression={$_.systemName};Label = "ServerName"},
                       @{Expression={$_.Name};Label = "SQLService"},
                       @{Expression={$_.StartName};Label = "Account"},
                       @{Expression={$_.StartMode};Label = "StartMode"},
                       @{Expression={$_.State};Label = "State"},
                       @{Expression={$_.DisplayName};Label = "ServiceName"}
                       $WMI|Export-csv $exportcsv -Append -NoTypeInformation
                                       

}
Catch
{
    Clear-Content $errorlog
     "Fail to get information $server +' ' + $RunTime :$_" |Out-File $errorlog -Append
}
}
})
Get-Job | Wait-Job | Out-Null
Remove-Job -State Completed

Friday, August 1, 2014

PowerShell - Get All SQL server VMs last reboot date/time

PowerShell ISE 3.0

The purpose of the following script is to make my DBA life easy when I manage 80 + SQL server VMs in the organization. The following script is to retrieve all SQL Server VM Last reboot date time without logging into each server and check eventlog.


Enjoy Scripting..

Step 1. Create a text file in which all sql server vm names. Save the file in your preferred. In my case the file is located at E:\PowerShell\SQLServerList\ folder
Step 2. run the script in powershell ISE or Schedule it in SQL Agent in your DBA test server instance


$($ServerList = 'E:\PowerShell\SQLServerList\SQLSvrList.txt'
$exportcsv ='E:\PowerShell\FindLastRebootDate\LastRebootDate.csv'
$servername = Get-Content $ServerList
$errorlog = 'E:\PowerShell\FindLastRebootDate\Error.txt'
if(!(test-path $ServerList))
{
    Write-Error "SQLSvrList.txt is not Found" -ea Stop
}
if(test-path $ServerList)
{
foreach($server in $servername){
Try{

$WMI=Get-WmiObject -ComputerName $server -Class win32_operatingsystem
$lastRebootTime = $WMI.ConvertToDateTime($WMI.LastBootUpTime)

$InfoRecord = New-Object -TypeName PSObject -Property @{
                    Server = $server;
                    LastRebootDateTime = $LastRebootTime;
                    };

$InfoRecord | Select Server,LastRebootDateTime


}
Catch
{
    Clear-Content $errorlog
    "Fail to get information $server +' ' + $RunTime :$_" |Out-File $errorlog -Append
}
}
})|Export-csv $exportcsv -noType
Get-Job | Wait-Job | Out-Null
Remove-Job -State Completed

PowerShell - Get All Scheduled Tasks in SQL Server VMs

 PowerShell ISE 3.0
The following script will collect tasks scheduled in Task Scheduler in windows server from all SQL server VMs. The purpose of my script is to know monthly reboot schedule of each server in the organization.

Enjoy Scripting..

Step 1. Create a text file in which all sql server vm names. Save the file in your preferred. In my case the file is located at E:\PowerShell\SQLServerList\ folder
Step 2. run the script in powershell ISE or Schedule it in SQL Agent in your DBA test server instance

$($ServerList = 'E:\PowerShell\SQLServerList\SQLSvrList.txt'
if(!(test-path $ServerList))
{
    Write-Error "SQLSvrList.txt is not Found" -ea Stop
}
if(test-path $ServerList)
{
$errorlog = 'E:\PowerShell\GetScheduleTask\Error.txt'
$exportcsv ='E:\PowerShell\GetScheduleTask\ScheduleList.csv'
$servername = Get-Content $ServerList
foreach($server in $servername){
Try{
Clear-Content $exportcsv
$schedule = new-object -com("Schedule.Service")
$schedule.connect($server)
$tasks = $schedule.getfolder("\").gettasks(0)
$tasks |select @{Name="Server";Expression={$server}},Name,LastRunTime,NextRunTime,@{Name="RunAs";Expression={[xml]$xml = $_.xml ; $xml.Task.Principals.principal.userID}}
}Catch
{
    Clear-Content $errorlog
    "Fail to get information $server +' ' + $RunTime :$_" |Out-File $errorlog -Append
}
}
})|Export-csv $exportcsv -noType
Get-Job | Wait-Job | Out-Null
Remove-Job -State Completed

Friday, December 13, 2013

Powershell - Copy .bak files

Copy .bak files from Local drive in SQL server to Central share


If you like command line scripting, you will like powershell. We have .bak files located on a backup drive on SQL server. They need to be copied to central share location for disaster recovery. I created the following powershell code. It is scheduled in SQL Agent. One tricky part is if  SQL job agent does not throw errors due to the central share does not exist or files do not not exit. So, we need to add error handling to let us know if the job fails.

cd c:
$originalpath = "S:\SQL\backup\"
$Destinationpath = "\\backups\bak\"
$filespath = "$Destinationpath\backup"
if (!(test-path $filespath))
{
    
    Write-Error "File Path error" -ea Stop
}

if(test-path $filespath)
{
    Remove-item $filespath -recurse -ea STOP
    Try
    {
        Copy-Item -Path $originalpath -filter *.bak -Destination $Destinationpath -force -Recurse -ea STOP -Errorvariable myError
    }
    Catch
    {
        Write-Error "Job Failure with $myError" -ea Stop
    }
   
}

Friday, April 19, 2013

Powershell - Remote

Powershell to remote to computers to get SQL server versions

$($servers = Import-Csv c:\centers.csv
$errorlog = "C:\Error.txt"
foreach($server in $servers){
Try
{
$con = ("server=" + $server.Host_Name + "\sqlexpress;database=master;Integrated Security=sspi")
$cmd = "select serverproperty('servername') as Name,serverproperty('productversion') as Version,serverproperty('productlevel') ServicePack,serverproperty('edition') as Edition"
$da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd,$con)
$dt = New-Object System.Data.DataTable
$da.fill($dt) | out-null
$dt
}
Catch
{
"Fail to remote to $server :$_" |add-Content $errorlog
}
})| Export-csv C:\SQLServerVersion.csv -NoTypeInformation

How to add a Database to AlwaysOn Availability Group with four different options

To add a database to an existing AlwaysOn availability group, MS has given us four options to choose from Automatic seeding Full database an...