Sign in to follow this  
Followers 0

Continue after reboot

14 posts in this topic

Posted (edited)

I have seen a few requests for the ability to continue a script after a reboot. I do this all the time, especially during holiday shutdown each year when I have a laundry list of tasks to perform on all systems. I have had as many as 40+ tasks, many of which reboot themselves, or won't continue if they see another installation that has not reboot yet (gotta love Microsoft).

Here is the shell script that I used to get it done.

Version 1

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Fileversion=0.0.0.0
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=y
#AutoIt3Wrapper_Run_Tidy=y
#AutoIt3Wrapper_Run_Obfuscator=y
#Obfuscator_Parameters=/striponly
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#cs ----------------------------------------------------------------------------

    Project Name: SystemCleanup
    Description: Runs a battery of tasks for annual cleanup
    Creation Date: 11/23/2010
    AutoIt Version: v3.3.6.1
    Author: David Williams (WILLICHAN)
    website: http://www.autoitscript.com/forum/user/6652-willichan/

#ce ----------------------------------------------------------------------------

Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declare
Opt("TrayAutoPause", 0) ;0=no pause, 1=Pause
Opt("TrayMenuMode", 0) ;0=append, 1=no default menu, 2=no automatic check, 4=menuitemID  not return
Opt("TrayIconHide", 0) ;0=show, 1=hide tray icon

Global Const $MyName = StringLeft(@ScriptName, StringInStr(@ScriptName, ".", 0, -1) - 1) ;get just the name portion of the script/exe name
Global Const $MyMutex = $MyName & "-4C4FE209743F270A" ;name the mutex for this app.  I create a new random number for each script I write to go in the quotes"
Global Const $MyVersion = FileGetVersion(@ScriptFullPath)
If _MutexExists($MyMutex) Then Exit ;exit if another instance of this app is running

#include <Debug.au3>
#include <misc.au3>

Global Const $CompanyName = "WilliWare" ;Change this to whatever you want.
Global Const $LogFileName = "c:\" & $MyName & ".log" ;Wherever you want it
; these next seven(7) constants are used for setting up auto-logon for reboots
;This can be a security risk if this script moves out of your own hands
;use caution
Global Const $UseAutoLogin = True ;set to false if you don't want to use
Global Const $mydomain = "mydomain" ;use @ComputerName for local accounts
Global Const $myusername = "myusername"
Global Const $mypassword = "mypassword"
Global Const $LegalNoticeCaption = "Legal Notice"
Global Const $LegalNoticeText = "This is my legal notice text"
Global Const $DefaultDomain = "mydomain" ;This is probably the same as $mydomain, but just in case...

;;;; You only need this if one of your stages requires admin rights (which mine usually do
If Not IsAdmin() Then
    MsgBox(48 + 262144, $MyName & " Error", "This utility requires local admin rights." & @CRLF & "Please log back in as a local administrator")
    Shutdown(4 + 16)
EndIf

;;;; I like my scripts to be version aware.  This way, thing restart from the
;;;; beginning again next year when I put out the new battery of cleanups.
;;;; I just set the AutoItWrapper to auto increment the version number.
;;;; If a new version is detected, reset and start from the beginning
;;;; if not new, pick up where we last left off
Global $lastver = RegRead("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Version")
If @error Then $lastver = "0.0.0.0"
If _VersionCompare($MyVersion, $lastver) = 1 Then
    RegWrite("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Version", "REG_SZ", $MyVersion)
    RegWrite("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Stage", "REG_DWORD", 0)
EndIf

;;;; Start the log file (optional
If @Compiled Then
    FileWrite($LogFileName, $CompanyName & " " & $MyName)
    FileWriteLine($LogFileName, " - " & @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC)
Else
    _DebugSetup($CompanyName & " " & $MyName & " - Status")
EndIf

;;;; What stage are we on?
Global $stage = RegRead("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Stage")
If @error Then $stage = 0

_SetAutoLogin()


;;;; now for the framework of the script
While True
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; WARNING:  The whole things ends when a number is not found, ;;
    ;;         so don't skip any digits                       ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    Switch $stage
        Case 0
            _Status("Installing Application A")
            _InstallApplicationA()
        Case 1
            _Status("Installing Application B")
            _InstallApplicationB()
        Case 2
            _Status("Installing Application C")
            _InstallApplicationC()
        Case Else
            ;All Done
            _Status("Done")
            _ClearAutoLogin()
            Shutdown(2 + 16) ;I like to force a reboot when I am done.  Comment out if you don't.
            Exit
    EndSwitch
    _NextStage()
WEnd

;;;; put the meat and potatoes functions here.
Func _InstallApplicationA()
    MsgBox(0, "Application A", "I am an application that does not require an immediate reboot." & @CRLF & "Let's continue without rebooting")
EndFunc   ;==>_InstallApplicationA

Func _InstallApplicationB()
    ;This stage can run, re-run, and reboot all it wants, as long as you have some way to know when it is done.
    ;I have some stages (like Microsoft Updates) that require several reboots before done
    If FileExists("C:\WilliWareDemo.txt") Then Return ;have some way of checking to see if you are already done with this stage so you do not end up in a reboot loop
    MsgBox(0, "Application B", "I do require an immediate reboot." & @CRLF & "Let's reboot, then continue on")
    FileWriteLine("c:\WilliWareDemo.txt", "I am part of a demo.  You can deleteme")
    Shutdown(2)
    Exit
EndFunc   ;==>_InstallApplicationB

Func _InstallApplicationC()
    MsgBox(0, "Application C", "I am an application that does not require an immediate reboot." & @CRLF & "Let's continue without rebooting")
EndFunc   ;==>_InstallApplicationC

;;;; supporting functions are here
Func _NextStage()
    $stage += 1
    RegWrite("HKEY_LOCAL_MACHINE\Software\" & $CompanyName, $MyName & "Stage", "REG_DWORD", $stage)
EndFunc   ;==>_NextStage

Func _SetAutoLogin()
    FileCreateShortcut(@ScriptFullPath, @StartupCommonDir & "\" & $MyName & ".lnk", @ScriptDir)
    If $UseAutoLogin Then
        _Status("Setting auto login")
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Userinit", "REG_SZ", "C:\WINDOWS\system32\userinit.exe,")
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", "REG_SZ", "explorer.exe")
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", $mydomain)
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", $myusername)
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword", "REG_SZ", $mypassword)
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon", "REG_SZ", "1")
        RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption")
        RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText")
    EndIf
EndFunc   ;==>_SetAutoLogin

Func _ClearAutoLogin()
    FileDelete(@StartupCommonDir & "\" & $MyName & ".lnk")
    If $UseAutoLogin Then
        _Status("Clearing auto login")
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", $DefaultDomain)
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", "")
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption", "REG_SZ", $LegalNoticeCaption)
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText", "REG_SZ", $LegalNoticeText)
        RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword")
        RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon")
    EndIf
EndFunc   ;==>_ClearAutoLogin

Func _Status($msg)
    If @Compiled Then
        SplashTextOn($CompanyName & " " & $MyName & " - Status", "Stage " & $stage & ":  " & $msg, 500, 100, -1, -1, 2 + 16 + 32)
        FileWriteLine($LogFileName, "Stage " & $stage & ":  " & $msg)
    Else
        _DebugOut("Stage " & $stage & ":  " & $msg)
    EndIf
EndFunc   ;==>_Status

Func _MutexExists($sOccurenceName)
    ;Credit goes to martin for this function
    Local $ERROR_ALREADY_EXISTS = 183, $handle, $lastError
    $sOccurenceName = StringReplace($sOccurenceName, "\", "")
    $handle = DllCall("kernel32.dll", "int", "CreateMutex", "int", 0, "long", 1, "str", $sOccurenceName)
    $lastError = DllCall("kernel32.dll", "int", "GetLastError")
    Return $lastError[0] = $ERROR_ALREADY_EXISTS
EndFunc   ;==>_MutexExists

------

Here's my new version. Some people had trouble remembering not to skip numbers, or to keep them in order, so this one puts it all in an array, so you don't have to manually keep track of task IDs.

Version 2

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Fileversion=0.0.0.1
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=y
#AutoIt3Wrapper_Run_Tidy=y
#AutoIt3Wrapper_Run_Obfuscator=y
#Obfuscator_Parameters=/striponly
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

#cs ----------------------------------------------------------------------------

    Project Name: SystemCleanup
    Description: Runs a battery of tasks for annual cleanup
    Creation Date: 11/23/2010
    AutoIt Version: v3.3.8.0
    Author: David Williams (WILLICHAN)
    website: http://www.autoitscript.com/forum/user/6652-willichan/

#ce ----------------------------------------------------------------------------

If StringInStr("|WIN_2008R2|WIN_2008|WIN_2003|WIN_XPe", "|" & @OSVersion & "|") Then Exit ;don't run on servers

Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declare
Opt("TrayAutoPause", 0) ;0=no pause, 1=Pause
Opt("TrayMenuMode", 0) ;0=append, 1=no default menu, 2=no automatic check, 4=menuitemID  not return
Opt("TrayIconHide", 0) ;0=show, 1=hide tray icon

Global Const $MyName = StringLeft(@ScriptName, StringInStr(@ScriptName, ".", 0, -1) - 1) ;get just the name portion of the script/exe name
Global Const $MyMutex = $MyName & "-10371BD27CD14632" ;name the mutex for this app
Global Const $MyVersion = FileGetVersion(@ScriptFullPath)
If _MutexExists($MyMutex) Then Exit ;exit if another instance of this app is running

Global Const $MyTitle = "System Cleanup"
Global Const $MySettingsRegPath = "HKEY_LOCAL_MACHINE\Software\MadeByMe"
Global Const $StageSettingRegStage = "SystemCleanupStage"
Global Const $StageSettingRegVer = "SystemCleanupVersion"
Global Const $LogFilePath = @DocumentsCommonDir & "\mytuneup.log"

If Not IsAdmin() Then
    MsgBox(48 + 262144, $MyTitle & " Error", "This utility requires local admin rights." & @CRLF & @UserName & " does not have proper access to run this script." & @CRLF & "Please correct this issue and log in again.")
    Shutdown(4 + 16)
EndIf

;;;;;
;; List tasks to be performed here
;; They will be executed in order
;; ex:  _AddTask("function", "message")
;; where function is the name of the function to call that will do the work
;; and message is the message that will be displayed in the status screen
;; and/or log file.
;;;;;
Global $tasklist[1][2] = [[0, 0]]
_AddTask("_Task1", "Doing whatever my first task is.")
_AddTask("_Task2", "This is my secont thing to accomplish.  I will need to reboot.")
_AddTask("_Task3", "Yet another thing to get done.")
;;;;;
;; end task list
;;;;;

Func _Task1()
    MsgBox(0, $MyTitle, "This is task #1. No reboot required.")
EndFunc   ;==>_Task1

Func _Task2()
    If FileExists("c:\task2marker.txt") Then
        MsgBox(0, $MyTitle, "Looks like task #2 completed ok.  Moving on.")
    Else
        MsgBox(0, $MyTitle, "This is task #2. Reboot required.")
        FileWriteLine("c:\task2marker.txt", "test")
        Shutdown(2 + 4)
    EndIf
EndFunc   ;==>_Task2

Func _Task3()
    MsgBox(0, $MyTitle, "This is task #3. No reboot required.")
EndFunc   ;==>_Task3


Global $lastver = RegRead($MySettingsRegPath, $StageSettingRegVer)
If @error Then $lastver = "0.0.0.0"
If _VersionCompare($MyVersion, $lastver) = 1 Then
    RegWrite($MySettingsRegPath, $StageSettingRegVer, "REG_SZ", $MyVersion)
    RegWrite($MySettingsRegPath, $StageSettingRegStage, "REG_DWORD", 0)
EndIf
Global $stage = RegRead($MySettingsRegPath, $StageSettingRegStage)
If @error Then $stage = 0
FileWrite($LogFilePath, $MyTitle)
FileWriteLine($LogFilePath, " - " & @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC)

_SetAutoLogin()
RegWrite("HKEY_CURRENT_USER\Control Panel\Desktop", "ScreenSaveActive", "REG_SZ", 0)
RegDelete("HKEY_CURRENT_USER\Control Panel\Desktop", "SCRNSAVE.EXE")
While True
    If $stage > $tasklist[0][0] Then
        ;All Done
        _Status("Done")
        _ClearAutoLogin()
        MsgBox(64 + 262144, $MyTitle, "System cleanup has completed" & @CRLF & "Click OK to restart the system")
        Shutdown(2 + 4 + 16)
        Exit
    Else
        _Status($tasklist[$stage][1])
        Call($tasklist[$stage][0])
    EndIf
    _NextStage()
WEnd

Func _NextStage()
    $stage += 1
    RegWrite($MySettingsRegPath, $StageSettingRegStage, "REG_DWORD", $stage)
EndFunc   ;==>_NextStage

Func _SetAutoLogin()
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Userinit", "REG_SZ", "C:\WINDOWS\system32\userinit.exe,")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", "REG_SZ", "explorer.exe")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", "admindomain"); I use the machine name here for a local admin account
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", "adminlogon")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword", "REG_SZ", "adminpassword")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon", "REG_SZ", "1")
    RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption")
    RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText")
EndFunc   ;==>_SetAutoLogin

Func _ClearAutoLogin()
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultDomainName", "REG_SZ", "mydomain")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultUserName", "REG_SZ", "")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword", "REG_SZ", "")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon", "REG_SZ", "")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeCaption", "REG_SZ", "LEGAL NOTICE") ; Whatever your company policy dictates here
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "LegalNoticeText", "REG_SZ", "Legal message here") ; Whatever your company policy dictates here
    RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "DefaultPassword")
    RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "AutoAdminLogon")
EndFunc   ;==>_ClearAutoLogin

Func _Status($msg)
    SplashTextOn($MyTitle & " - Status", "Stage " & $stage & ":  " & $msg, 500, 100, -1, -1, 2 + 16 + 32)
    FileWriteLine($LogFilePath, "Stage " & $stage & ":  " & $msg)
EndFunc   ;==>_Status

Func _AddTask($task, $message)
    Local $tcount = $tasklist[0][0] + 1
    ReDim $tasklist[$tcount + 1][2]
    $tasklist[0][0] = $tcount
    $tasklist[$tcount][0] = $task
    $tasklist[$tcount][1] = $message
EndFunc   ;==>_AddTask

Func _MutexExists($sOccurenceName)
    ;Credit goes to martin for this function
    Local $ERROR_ALREADY_EXISTS = 183, $handle, $lastError
    $sOccurenceName = StringReplace($sOccurenceName, "\", "")
    $handle = DllCall("kernel32.dll", "int", "CreateMutex", "int", 0, "long", 1, "str", $sOccurenceName)
    $lastError = DllCall("kernel32.dll", "int", "GetLastError")
    Return $lastError[0] = $ERROR_ALREADY_EXISTS
EndFunc   ;==>_MutexExists

------

MSUpdates Module

This module was written for the Version 1 script, and has not been tested for Version 2.

First, you will need to download WuInstall from http://www.wuinstall.com/index.php/en/free.

(This is an excellent utility, so I highly recommend purchasing a Pro copy)

Unzip and place the WUInstall.exe file in a folder beneath your script called 3rdParty.

Func _InstallWindowsUpdates()
    Local $DBQ = '"'
    Local $res
    Local $tfile = _TempFile(@TempDir, "~", ".exe")
    FileInstall("3rdParty\WUInstall.exe", $tfile, 1)
    $res = RunWait($tfile & " /install /criteria " & $DBQ & "IsAssigned=1 and IsHidden=0 and IsInstalled=0 and Type='Software'" & $DBQ, @TempDir)
    FileDelete($tfile)
    If $res < 2 Or $res > 4 Then Shutdown(6)
EndFunc   ;==>_InstallWindowsUpdates

--Edit--

Added Version 2 of script

modified log path in Version 2 (see posts 5&6)

Added MSUpdates module

Edited by willichan
notime likes this

Share this post


Link to post
Share on other sites



Posted

Nice! Haven't tested yet but I did something similar too.

Share this post


Link to post
Share on other sites

Posted

I did a rewrite of this shell to accommodate some people that were editing my scripts, but couldn't remember to keep tasks IDs consecutive. This new one is going into use for 2011 end-of-year cleanup. See post #1 for both versions.

Share this post


Link to post
Share on other sites

Posted

Thanks for sharing, ill have a look and report back.

Share this post


Link to post
Share on other sites

Posted

I personally wouldn't hard-code the C: drive destination but instead opt for saving to a different location such as @AppDataCommonDir.

Share this post


Link to post
Share on other sites

Posted

I personally wouldn't hard-code the C: drive

I agree with you. This script comes from an internal end-of-year cleanup script, and the log file location was decided on "by committee", and gets deleted in a few days anyway. I'll change it in the top post though, when I get a few minutes this morning.

Share this post


Link to post
Share on other sites

Posted

Very nice, thanks for sharing!!!

Regards,

João Carlos.

Share this post


Link to post
Share on other sites

Posted

Great stuff look forward to testing

Share this post


Link to post
Share on other sites

Posted

Ok. I have had alot of people contacting me, both from the forum and from without, wanting the MS Updates script. I went ahead added it to post #1.

I am glad to see that so many people are able to make use of this shell script.

Share this post


Link to post
Share on other sites

Posted

Nice post. I was wondering how would you edit script #1 to remove versioning, but keep everything else. For example, I still want it to go through all the stages instead of going straight to stage 3 (based on your example).

Share this post


Link to post
Share on other sites

Posted

That kind of defeats the purpose of the script.  The idea behind this script is to be able to continue where you left off after a reboot.

If you want to start from stage one every time you can just call a regular script?

Or am I misunderstanding your question?

Share this post


Link to post
Share on other sites

Posted

So I just saw this and I have not tested, but reading through the code, I have a couple questions.

How do you autostart the app on reboot? Do you have UAC enabled? 

Share this post


Link to post
Share on other sites

Posted

We have UAC turned off for all of our machines, and have a special domain account set up for doing our cleanups.  It has sufficient rights for all of the tasks needed, and has the cleanup script followed by a mandatory reboot in its login script.  That way, we just log in, and walk on to the next PC.  Then cycle back after covering the floor to make sure the script completed.

Share this post


Link to post
Share on other sites

Posted (edited)

Nice.  Did not know about ther userinit registry key.  I always over complicated things with scheduled tasks creation|deletes.

Edited by jdelaney

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0