Solved

I need help with an AD VBScript

Posted on 2004-09-17
37
167 Views
Last Modified: 2010-04-12
I have one big folder with over 1000 user folders.

I also have two seperate OU's in which those users reside.

I need a script that can compare the AD OU's to that folder and give me a simple report of what user is in which OU.

All of that user folders are based on their domain login name (I.E. jared.luker), so if the script can check the domain login name against this user folder and report whether it's in OU1 or OU2, this would make my life in the next week much easier!

Thanks!

Jared
0
Comment
Question by:Jared Luker
  • 21
  • 14
  • 2
37 Comments
 
LVL 16

Expert Comment

by:mdiglio
ID: 12084321
Hello,
I'm not sure if I understasnd the question correctly,
but if all you need is some sort of list stating the contents of an ou
you can open ad users and computers >> right click the ou >> select export list.

If you need something else the script below will export user name for you into as text file.
I don't know how your ou structure is setup so for now you will have to run this once for
ou1 and once for ou2

'!!!Begin Copy
const ADS_SCOPE_SUBTREE =2
Const ADS_SCOPE_ONELEVEL = 1
Const ForAppending = 8
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
'!!!!!text file will be created on your C: drive...change to match your needs !!!!!
Set objTextFile = objFSO.OpenTextFile("c:\ou1.txt", ForWriting, True)

Set cnn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
' Open the connection.
cnn.Provider = "ADsDSOObject"  ' This is the ADSI OLE-DB provider name
cnn.Open "Active Directory Provider"
' Create a command object for this connection.
Set cmd.ActiveConnection = cnn

' Compose a search string.
'!!!!you will have to change this line to match your OU Design!!!!!
strQuerY = "ou=OU1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"

cmd.CommandText = "select name from 'LDAP:// " & strQuerY & ""
cmd.Properties("Page Size") = 1000
cmd.Properties("Timeout") = 30
cmd.Properties("Searchscope") = ADS_SCOPE_ONELEVEL
cmd.Properties("Cache Results") = False

Set rs = cmd.Execute
   
On Error Resume Next
 
Do While Not rs.EOF
   
  objTextFile.WriteLine rs.Fields("Name")
  rs.MoveNext
Loop
wscript.echo "Done"
0
 
LVL 8

Expert Comment

by:jwarnken
ID: 12084649
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12084680
That's close to what I need.

If there is a way to take the output of the script above, and then bump it against either the directory itself, or a text file with all the directory names and just tell me which names exist in both, then I would have what I needed.

I'm just trying to avoid having to process both the names in the OU and manually bump those names up against 2,993 folders that are in the one directory.

Maybe it would help to know why I need this.  Right now, there are two different orgs sharing this one user folder.  The orgs are splitting, and I need a way of determining which org the folder belongs to.  That way I can use robocopy to copy just the folder that I need for the new org instead of having to copy them all and sort it out later.

It would also be really useful if I could get a third list of names that don't don't exist in either OU (people that have moved on, or quit/retired).

Thanks
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12085258
does the output of the text file in the first script match the folder names?

You might get the answer your looking for quicker ( and a better one)
if you post a 0 point link to this question in the
programming >> languages >> Visual Basic section

0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12085356
It does now.  I had to change it from the display name to the sAMAccountName, because the folders are based on firstname.lastname.  The folders are all firstname.lastname.
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12086876
Hey...I didn't abonon you.
I am waiting to see other suggestions.
If we don't hear from anyone I can do it for you...
just won't be too pretty :)
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12087335
haha... no problem!
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12094155
So now we need to take the names that were generated from the 1st script and
see if that name exists in the folder list?

Would it help to run the robocopy command in the middle of the do-while loop above?
That way we will be enumerating every user in the ou and then copying the folder using the samaccountname
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12095458
that would be awesome!

0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12096359
'!!Beign Copy
const ADS_SCOPE_SUBTREE =2
Const ADS_SCOPE_ONELEVEL = 1
Const ForAppending = 8
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
'!!!!!text file will be created on your C: drive...change to match your needs !!!!!
'Not sure if you even need this line with our new method
'I have put it in as an error control in case a samAccountName does not
'have a matching folder.
'It is used in the IF statement nested in the Do-while loop

Set objTextFile = objFSO.OpenTextFile("c:\ou1NoFolder.txt", ForWriting, True)

Set cnn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
' Open the connection.
cnn.Provider = "ADsDSOObject"  ' This is the ADSI OLE-DB provider name
cnn.Open "Active Directory Provider"
' Create a command object for this connection.
Set cmd.ActiveConnection = cnn

' Compose a search string.
'!!!!you will have to change this line to match your OU Design!!!!!
strQuerY = "ou=OU1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"

cmd.CommandText = "select samaccountname from 'LDAP:// " & strQuerY & ""
cmd.Properties("Page Size") = 1000
cmd.Properties("Timeout") = 30
cmd.Properties("Searchscope") = ADS_SCOPE_ONELEVEL
cmd.Properties("Cache Results") = False

Set rs = cmd.Execute
   
On Error Resume Next
 
Do While Not rs.EOF
  strName = rs.Fields("samaccountname")
     If objFSO.FolderExists("\\oldir\" & strName & " ") Then
        wshShell.Run("cmd.exe /c robocopy \\olddir\ " & strName  & "  \\newdir\ " & strName &"")
'!!!SEE Below!!!!!
        wscript.sleep 15000
      else
        objTextFile.WriteLine strname
     end if
   rs.MoveNext
Loop
wscipt.echo "Done"

'!!!End Copy

This robocopy command is not complete.
I am guessing you already have picked out the switches you want to use
so the end will look like something like this:
wshShell.Run("cmd.exe /c robocopy \\olddir\ " & strName  & "  \\newdir\ " & strName &"/E /ZB /COPY:DAT /XO")

Also I have put a sleep for 15 seconds.
It sounds like you have a lot of folders to copy.
Not knowing if it is a local copy, remote copy, or how large the folders are I cannot
judge how long it will take.
If we don't let the system finish running the robocopy command we will keep piling up those running processes.
So we might get hundreds of robocopy commands runnning at the same time.
Did I explain that clearly?
If we need to we can check the size of the folders first and then
set a time to sleep based upon that result

Please run this in a testing environment first.
Like I said I was really hoping we could get a programmer to write this for you.
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12096372
please comment out the line right above the Do-While loop....
on error resume next

 
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12096414
As for the other part of what you are trying to do....checking for the abondoned folders.

Are the 2 OUs on the same level?
If so are there any more ous with users below them?

My plan is to change the output of the first script to make it a comma seperated file.
We could go ahead and make two files or one larger file.
I am trying to find out what search scope to use; ADS_SCOPE_SUBTREE or ADS_SCOPE_ONELEVEL

We will then run the file(s) against the output of the script below:

'!!!Begin Copy
Const ForAppending = 8
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("c:\FolderNames.txt", ForWriting, True)

'!!!Change this line to match your needs!!!
'!!!point it to wherever the users folders are
Set objFolder = objFSO.GetFolder("C:\Folder")
Set colSubfolders = objFolder.Subfolders
For Each objSubfolder in colSubfolders
   strFolder = strFolder & objSubfolder.Name & " , "
Next
objTextFile.WriteLine strFolder
'!!!! End Copy
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12096755
The users are in 2 seperate OU's, but do not have sub-OU's.

One is in ou1\users
the other is in ou2\users

ALL users are in those two OU's.

Thanks
0
 
LVL 16

Accepted Solution

by:
mdiglio earned 500 total points
ID: 12098673
ok sorry for the mess and so many different scripts

This script below will work if both of your OUs are on the same level
e.g. both ou1 and ou2 are under an ou named TopOU
If thats not the case let me know and it will be a simple change

'!!Beign Copy
const ADS_SCOPE_SUBTREE =2
Const ADS_SCOPE_ONELEVEL = 1
Const ForAppending = 8
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
'!!!!!text file will be created on your C: drive...change to match your needs !!!!!

Set objTextFile = objFSO.OpenTextFile("c:\ou1_OU2.txt", ForWriting, True)

Set cnn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
' Open the connection.
cnn.Provider = "ADsDSOObject"  ' This is the ADSI OLE-DB provider name
cnn.Open "Active Directory Provider"
' Create a command object for this connection.
Set cmd.ActiveConnection = cnn

' Compose a search string.
'!!!!you will have to change this line to match your OU Design!!!!!
'this will work only if both OUs are under the same OU in this case the 'topOU'

strQuerY = "ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"

cmd.CommandText = "select samaccountname from 'LDAP:// " & strQuerY & ""
cmd.Properties("Page Size") = 1000
cmd.Properties("Timeout") = 30
cmd.Properties("Searchscope") = ADS_SCOPE_SUBTREE
cmd.Properties("Cache Results") = False

Set rs = cmd.Execute
   
On Error Resume Next
 
Do While Not rs.EOF
  strName = strname & rs.Fields("samaccountname") & ","
Loop
objTextFile.WriteLine strname
wscipt.echo "Done"

'!!!End Copy
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12098686
Finally this will comapre the 2 text files
one with the users from the ou against the list of folder names
and it will put the orphaned folder names into a text file named orphaned.txt on
your c drive

Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
'The name of the comma seperated file that has all the
'users from ou1 and ou2 goes here
Set objTextFile = objFSO.OpenTextFile _
    ("c:\ou1_ou2.txt", ForReading)
Do Until objTextFile.AtEndOfStream
    strNextLine = objTextFile.Readline
    arrusers = Split(strNextLine, ",")
Loop
'The name of the comma seperated file that has all the
'folder names goes here
Set objTextFile2 = objFSO.OpenTextFile _
    ("c:\foldernames.txt", ForReading)
Do Until objTextFile2.AtEndOfStream
    strNextLine = objTextFile2.Readline
    arrfolderlist = Split(strNextLine, ",")
Loop

'!!!!!text file will be created on your C: drive...change to match your needs !!!!!
'thid will hold all the folders that do not have a matching username
Set objTextFile3 = objFSO.OpenTextFile("c:\orphaned.txt", ForWriting, True)

Dim blnFound As Boolean
 For i = 0 To UBound(arrfolderlist)
    blnFound = False
    For j = 0 To UBound(arrusers)
        If arrfolderlist(i) = arrusers(j) Then
            blnFound = True
        End If
    Next j
    If blnFound = False Then
       objTextFile3.WriteLine arrfolderlist(i)
    End If
Next i
wscript.echo "done"
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12098692
I think that is everything.
please ask me any questions you have because I threw a lot of
what must look like repeating code out there and made it very confusing.
I did say it wouldn't be pretty :)

0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12098844
I'll give it a shot!

Just as an FYI, if you put a ,4,true at the end of the .run line, it will wait for the processing robocopy to finish before it kicks off another process.  The ,4 tells it what kind of window to use, and the True is what tells it to wait.  For example:

wshShell.Run("cmd.exe /c robocopy \\olddir\ " & strName  & "  \\newdir\ " & strName &""),4,true

Thanks for your help.   I'll let you know how it goes.
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12099005
Hey Thanks!! I'm sure I'll have to use that sometime soon
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 17

Author Comment

by:Jared Luker
ID: 12126719
Ok... to answer your question from a while ago, ou1 and ou2 are not under the same ou.  It goes more like this:

top\org1\users
top\org2\SubOrg2\Users

Jared
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12127382
Good, i think you are still on track if you run the script I posted on
09/19/2004 07:01PM PDT to gather a comma seperated file of samaccountnames

these line snippets from that post will tell the script to gather
all samaccountnames for any user object located under what we have been calling the 'top' ou:
strQuerY = "ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"
and
cmd.Properties("Searchscope") = ADS_SCOPE_SUBTREE
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12127527
The only problem is that there are THOUSANDS of user accounts under topOU that I have nothing to do with (it's a very big AD).  I specifically need users from OU1 and OU2 as represented below:

strQuerY1 = "ou=users,ou=org1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"
strQuerY2 = "ou=users,ou=SubOrg2,ou=org1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"

Thanks!
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12127989
Alrighty then. We will make two text files and combine them:

>> once more copy and paste the code in my next post. change the
strQuerY1 = "ou=users,ou=org1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"
part to match

>>Change the text file name to something like ou1.txt

run the code >> open ou1.txt >> remove the comma at the very end of the file.

run the code again using this query
strQuerY2 = "ou=users,ou=SubOrg2,ou=org1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"
and change the text file name to something like ou2.txt.

combine the two text files to form one large comma seperated file.

Please Note this combined text file is used in my post from 09/19/2004 07:05PM PDT
( the name of the file that I have written in the script is OU1_OU2.txt )
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12128007
'!!Beign Copy
const ADS_SCOPE_SUBTREE =2
Const ADS_SCOPE_ONELEVEL = 1
Const ForAppending = 8
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
'!!!!!text file will be created on your C: drive...change to match your needs !!!!!

Set objTextFile = objFSO.OpenTextFile("c:\ou1.txt", ForWriting, True)

Set cnn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
' Open the connection.
cnn.Provider = "ADsDSOObject"  ' This is the ADSI OLE-DB provider name
cnn.Open "Active Directory Provider"
' Create a command object for this connection.
Set cmd.ActiveConnection = cnn

' Compose a search string.
'!!!!you will have to change this line to match your OU Design!!!!!
"ou=users,ou=org1,ou=topOU,dc=yourDomain,dc=com' WHERE objectCategory= 'user'"

cmd.CommandText = "select samaccountname from 'LDAP:// " & strQuerY & ""
cmd.Properties("Page Size") = 1000
cmd.Properties("Timeout") = 30
cmd.Properties("Searchscope") = ADS_SCOPE_ONELEVEL
cmd.Properties("Cache Results") = False

Set rs = cmd.Execute
   
On Error Resume Next
 
Do While Not rs.EOF
  strName = strname & rs.Fields("samaccountname") & ","
Loop
objTextFile.WriteLine strname
wscipt.echo "Done"

'!!!End Copy
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12135465
I don't think that VBScript likes this VB Code:

Dim blnFound As Boolean
 For i = 0 To UBound(arrfolderlist)
    blnFound = False
    For j = 0 To UBound(arrusers)
        If arrfolderlist(i) = arrusers(j) Then
            blnFound = True
        End If
    Next j
    If blnFound = False Then
       objTextFile3.WriteLine arrfolderlist(i)
    End If
Next i


I'm getting:

C:\vb\Untitled1.vbs(39, 14) Microsoft VBScript compilation error: Expected end of statement

Line 39 is the first dim line found above.

I have both OU's consolidated into one comma delimited file and I have a text file of all the folders.  I had to pull the text file of the folders into excel to make it comma delimited, but I got er' done.

Any idea why the script won't compile and run?
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12137599
oops you are right..
please change it
FROM
Dim blnFound As Boolean
TO
Dim blnFound
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12137792
C:\vb\Untitled.vbs(46, 10) Microsoft VBScript compilation error: Expected end of statement

that is the Next j line.  If I take out the j so that it just says next, it will continue only to give the same error for the Next i.

If I take out both the j and the i from the next lines, it will run through the script, but the resulting file will only have one name in it (the very last one on file)
0
 
LVL 8

Expert Comment

by:jwarnken
ID: 12137934
you are missing and END statement
either a End if or End sub or End Function

if you can not find it post the whole script
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12138010
The whole script:

Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
'The name of the comma seperated file that has all the
'users from ou1 and ou2 goes here
Set objTextFile = objFSO.OpenTextFile _
    ("c:\combined.txt", ForReading)
Do Until objTextFile.AtEndOfStream
    strNextLine = objTextFile.Readline
    arrusers = Split(strNextLine, ",")
Loop
'The name of the comma seperated file that has all the
'folder names goes here
Set objTextFile2 = objFSO.OpenTextFile _
    ("c:\foldernames.txt", ForReading)
Do Until objTextFile2.AtEndOfStream
    strNextLine = objTextFile2.Readline
    arrfolderlist = Split(strNextLine, ",")
Loop

'!!!!!text file will be created on your C: drive...change to match your needs !!!!!
'thid will hold all the folders that do not have a matching username
Set objTextFile3 = objFSO.OpenTextFile("c:\orphaned.txt", ForWriting, True)

Dim blnFound
 For i = 0 To UBound(arrfolderlist)
    blnFound = False
    For j = 0 To UBound(arrusers)
        If arrfolderlist(i) = arrusers(j) Then
            blnFound = True
        End If
    Next j
    If blnFound = False Then
       objTextFile3.WriteLine arrfolderlist(i)
    End If
Next i
wscript.echo "done"
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12138633
hey jared_luker,
sorry the problem isn't obvious to me right now.
If you have visual basic installed everything will compile and run fine.

I will keep looking and get back with you.

Hopefully jwarnken is a programmer :)
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12138772
alright, we need to change
FROM:
Next i
TO:
Next

and
From:
Next J
TO:
Next

So the end of the For Next loops should not have the variable i or j
Dim blnFound
 For i = 0 To UBound(arrfolderlist)
    blnFound = False
    For j = 0 To UBound(arrusers)
        If arrfolderlist(i) = arrusers(j) Then
            blnFound = True
        End If
    Next
    If blnFound = False Then
       objTextFile3.WriteLine arrfolderlist(i)
    End If
Next
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12138944
mdiglio...

Thanks, but I mentioned that I had tried that four posts above your last one! : )

I appreciate your hanging in there! : )
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12138988
ooops..clearly you did say that
earlier I had mentioned (maybe) one of the flaws in my script was an extra comma at the end of the files.
Perhaps when the 2 files were combined the extra comma stayed in.

Open the combined.txt file and do a search for ,,

You had mentioned that removing the j and the i above resulted in the last name being put ionto the orphaned.txt
Is that indeed an orphaned folder?

If you cut and paste that name to somewhere else in the file and rerun the script does it still show up in orphaned.txt
or does the last one in the fie constantly show up?
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12139061
There is no ,, in the whole file with the combined users OU.

I copied and pasted the name that shows up in the orphaned.txt from the folders text file into the users text file and it still showed up in orphans after running the script.
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12139076
ok...don't laugh
lets try this a different way

open your combined.txt file >> select all >> copy
now open Word >> paste >> perform a find and replace
we want to replace the commas , with the 'special' character for a paragraph ^p
(this next step may not be needed...)
copy and paste the new longer file into excel and sort alphabetically by name.
Copy and paste the newly sorted list into a file called 1.txt

repeat for the foldernames.txt file utliamtely calling it 2.txt

now download and install this program called Comapreit
http://www.grigsoft.com/wincmp.htm
compare the 2 files and the missing ones will be in red

you can stop laughing now
0
 
LVL 17

Author Comment

by:Jared Luker
ID: 12139202
Haha... your killing me petey.... : ) (from the sandlot in case you havn't seen it)

This is what I ended up doing:

Imported the two lists into seperate tables in access.  A guy I carpool with gave me a VERY simple sql statement in a query that gave me the exact results that I was looking for.  That query was easily exported to a text file for future use.

I appreciate everyones efforts.  I would still like to see how this type of compare would be done with VBScript if anyone is still working on it.

Thanks,

Jared
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12139382
Cool...glad you got it working
0
 
LVL 16

Expert Comment

by:mdiglio
ID: 12139443
hey here is a shell of a script that does what we were looking for

Dim fso, oldRange, newRange, oldIP, newIP
Dim oldIPRec, newIPRec, arrayNewIP, I

Set fso = CreateObject("Scripting.FileSystemObject")
Set oldRange = fso.GetFile("c:\combined.txt")
Set newRange = fso.GetFile("c:\foldernames.txt ")
Set oldIP=fso.OpenTextFile(oldRange, 1, False)
Set newIP=fso.OpenTextFile(newRange, 1, False)
oldIPRec = oldIP.Read(oldRange.Size)
newIPRec = newIP.Read(newRange.Size)
oldIP.Close
newIP.Close
arrayNewIP = split(newIPRec, VbCrLf)

For I = 0 to UBound(arrayNewIP) - 1
If InStr(oldIPRec, arrayNewIP(I)) = 0 then
 Wscript.Echo  arrayNewIP(I)
End IF
Next

'this method assumes that your foldernames.txt file has more names listed than your combined.txt file
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

NTFS file system has been developed by Microsoft that is widely used by Windows NT operating system and its advanced versions. It is the mostly used over FAT file system as it provides superior features like reliability, security, storage, efficienc…
Moving applications to the cloud or switching services to cloud-based ones, is a stressful job.  Here's how you can make it easier.
This video discusses moving either the default database or any database to a new volume.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now